在 C++ 线程对象中重新绑定 *this,移动构造函数,移动赋值

Rebind *this in C++ thread object, move constructor, move assignment

我有一个 class 和一个使用 class 成员的线程对象。

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')
          }
      })
    {
    }
};

问题:如何实现move赋值/构造函数,让thread对象引用新的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 对象。这是一个提示:虽然您可以编写自己的移动构造函数,用旧对象的 value 初始化新对象的 a,但行为不会是原子的! (您 必须在线程之间同步以 发布 新原子对象的地址。)

所以不要动它。这立即意味着原子对象不能是您的可移动对象的(直接)成员class;下一个最简单的事情(除了让它在 lambda 本地,这可能是不可取的)是通过 unique_ptr(已经有所需的 movability-but-not-copyability)拥有它。然后 lambda 可以捕获原始指针以避免引用可能悬空的 this(的子对象):

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;
          }
      })
    {
    }
};

默认走法constructor/assignment是正确的。 (请注意,如果线程仍然是 运行,则赋值调用 terminate,这是有道理的,因为您刚刚释放了它正在使用的 atomic_int!)