【问题标题】:Why is copying or assigning objects of this class considered dangerous?为什么复制或分配此类的对象被认为是危险的?
【发布时间】:2021-08-30 04:27:48
【问题描述】:

来自 Anthony Williams 的“C++ Concurrency in Action”。

作者定义了一个thread_guard 类,该类在构造时传递对std::thread 的引用,并在销毁时尝试join() 同一线程。

这是定义

class thread_guard
{
    std::thread& t;
    public:
        explicit thread_guard(std::thread& t_):t(_t){}
    ~thread_guard()
    {
        if(t.joinable())
        {
           t.join();
        }
    }
    thread_guard(thread_guard const&)=delete;  // why?
    thread_guard operator=(thread_guard const&)=delete;  // why?
};

struct func; // function object, definition not included here
void f()
{ 
    int some_local_state = 0;
    func my_func(some_local_state); // passing in a local variable
    std::thread t(my_func);

    // ensure that thread finishes before exiting f()
    thread_guard tg(t);  
    do_something_in_current_thread();
}

我的问题是为什么不允许使用复制构造函数和赋值运算符(使用delete)? 作者说复制会很危险,因为thread_guard 复制“可能会超过它加入的线程的范围”。 但我很困惑——这难道不是一种风险,即使是原始对象(对象将超过线程的范围)?这不就是为什么在析构函数中有一个检查,if t.joinable()

我在这里错过了什么基本的东西。

(相关:thread_guard vs scoped_thread

【问题讨论】:

  • 线程保护副本可以在另一个线程中创建。然后它持有的原始线程被原始thread_guard加入......
  • ... 并且 thread_guard 副本在超出范围之前检查原始线程是否是 joinable()... 问题出在哪里?
  • if(t.joinable()) t.join(); 不是原子的,这就是问题所在。两个线程都可以完成检查,然后尝试加入。

标签: c++ multithreading c++11


【解决方案1】:

thread_guard 保护的std::thread 对象通过引用。因此,如果thread_guard 对象的寿命比std::thread 对象的寿命长,那么就有一个悬空引用,并且对t.joinable() 的调用是未定义的行为。

使thread_guard 不可复制使得在这种情况下更难结束:因为std::thread 对象和thread_guard 可能是本地范围的变量,那么为了将线程传递给守卫,线程必须先构建,这意味着它在大多数情况下都会被销毁。

注意:这些都不是关于线程本身的,纯粹是关于std::thread 对象

如果同一个std::thread对象有多个thread_guard对象,第一个被销毁的将在必要时调用t.join(),第二个将看到线程已经加入并且什么都不做。

如果std::thread 对象没有线程,无论是因为它是默认构造的、已经加入或分离的,还是它的线程被移动到另一个std::thread 对象,那么thread_guard 析构函数什么都不做。

【讨论】:

    【解决方案2】:

    给出的解释并不是最令人信服的理由 (imo)。

    每个线程应该只有 一个 thread_guard。使其不可复制意味着很难意外地拥有同一线程的两个守卫。

    预期的用例是线程和守卫都是自动存储持续时间对象,位于同一范围内,守卫在线程被销毁之前加入线程。没有必要复制守卫

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 2011-11-09
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 2014-11-29
      • 2012-02-06
      • 2016-02-14
      相关资源
      最近更新 更多