我有一个带有使用类成员的线程对象的类。

class MyClass
{
private:
    atomic_int a;
    thread t;

public:
    MyClass()
    : a(0),
      t([this]() // <- grab 'this' pointer
      {
          while(true)
          {
              sleep_for(milliseconds(1000));
              a++; // <- use 'a' field of the object (through 'this')
          }
      })
    {
    }
};

问题:如何实现移动分配/构造函数,以便线程对象引用新的MyClass对象?

天真的(不好的)实现:
class MyClass
{
public:
    MyClass(MyClass&& other)
    : a(other.a),
      t(other.t) // <- Thread object is moved to the new MyClass object
                 //    but it's still referencing the old 'this' pointer.
    {
    }
}

最佳答案

您无法移动atomic对象。这是一个提示:虽然您可以编写自己的move构造函数以将旧对象的a初始化为旧对象的unique_ptr,但行为不会是原子的! (您还必须在线程之间进行同步,以发布新的原子对象的地址。)

所以不要移动它。这立即意味着原子对象一定不能是可移动类的(直接)成员。接下来的最简单的事情(除了将其设置在lambda之外,这可能是不希望的)是通过this(已经具有所需的可移动性但不具有可复制性)来拥有它。然后,lambda可以捕获原始指针,以避免引用可能悬挂的terminate(的子对象):

class MyClass
{
private:
    unique_ptr<atomic_int> a;
    thread t;

public:
    MyClass()
    : a(new atomic_int(0)),
      t([a=a.get()]() // <- grab pointer to atomic
      {
          while(true)
          {
              sleep_for(milliseconds(1000));
              ++*a;
          }
      })
    {
    }
};

这样,默认的move构造函数/赋值是正确的。 (请注意,如果线程仍在运行,则分配调用atomic_int,这是有道理的,因为您只是重新分配了正在使用的ojit_code!)

关于c++ - 在C++线程对象中重新绑定(bind)* this, move 构造函数, move 赋值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49588418/

10-11 22:43
查看更多