在 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
!)
我有一个 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
!)