c++ - 我应该删除内部创建线程的类的复制构造函数和赋值运算符吗?

标签 c++ multithreading thread-safety copy-constructor

当一个类拥有线程和互斥对象时,是否存在任何潜在的危险情况,其中复制/赋值是危险的,这意味着应该删除复制构造函数和赋值?

考虑这个示例代码:

class A : B
{
    std::thread t;
    std::mutex m;

  public:
    A() : B() {}
    virtual ~A()
    {
        if (t.joinable())
            t.join();
    }

    // Should I delete cctor and assignment operator?

    virtual void Method()
    {
        t = std::thread([this] 
        {
            std::lock_guard<std::mutex> lck(m);
            ... // processing
        });
    }

    // Other methods that lock on mutex m
};

如果我理解正确的话,在 Method() 中创建的线程在 A 之外将不可见,这意味着使用默认 cctor 进行复制应该不会有问题,因为整个状态都会被复制。我的推理正确吗?

最佳答案

任何(扩展)状态包含指向自身的指针的类都必须具有已删除的拷贝/移动,或者必须编码该状态。

t = std::thread([this] 

上面的行在类的扩展状态下存储了一个指向 this 的指针。

因此,默认复制和移动是不合适的。删除是一种选择;小心翼翼地、可能代价高昂地编码另一个。

此外,线程和互斥体都是仅移动类型。因此拷贝将被隐式删除。

但是,您的移动分配/构造将由编译器编写并且错误。因此删除它们或修复它们。

<小时/>

没有类值类型的语言(如 Java/C#)有一个习惯用法,即拥有一个具有状态的类和一个处理该状态的线程。对于像 C++ 这样以值(value)为中心的语言来说,这是一个糟糕的计划。将您的状态存储在外部(例如,共享或唯一的 ptr),与您的线程共享(作为共享 ptr 或观察 ptr),突然间默认移动就有意义了。

如果不这样做,你的对象就会变得无柄——无法安全地移动——这会削弱许多伟大的 C++ 习惯用法,或者强制外部智能指针包装。

关于c++ - 我应该删除内部创建线程的类的复制构造函数和赋值运算符吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48137834/

相关文章:

c++ - 打印变量名称及其值的宏

java - 使用 ThreadLocal 与以 Thread 作为键的 HashMap

android - Java - 安卓 : Thread being called (run) twice

C++ ODBC 检查连接是否成功

c++ - read(2) 不在 EOF 时可以返回零吗?

c++ - 它是一个 gdb 错误吗?

python - list.append(foo) 可以不是线程安全的吗?

objective-c - 核心数据 : Freeze at the end of a save

multithreading - "Multi-process"与 "single-process multi-threading"用于软件模块通过消息进行通信

java - ConcurrentHashMap 和复合操作