安全移动 运行 访问其他成员的成员线程中的 lambda 对象
Safely moving objects that run a lambda in a member thread that accesses other members
我有一个 class,它有一个 std::thread
成员变量,它运行一个依赖于其他成员变量的 lambda 函数。
举个例子:
struct C {
C() {
thread_ = std::thread([this]() {
running_ = true;
while (running_) {
...
}
});
}
C(C&& rv) {
swap(rv);
}
void swap(C& rhs) {
std::swap(thread_, rhs.thread_); // step 1
std::swap(running_, rhs.running_); // step 2
}
std::thread thread_;
bool running_;
};
int main() {
C c;
C c2 = move(c); // Is c safely moved to c2?
}
- 移动此类物体的安全方法是什么?
- 移动操作后要指向哪个对象
[this]
。
- 在
step 1
之后 step 2
之前,在 lambda 的 while 循环中访问了哪个对象的 running_
?
虽然 std::thread
当然是可移动的,但这样做并不会神奇地修改任何引用它的指针,或者它包含的对象,如果有的话。
因此,即使在您移动 C
之后,包含的 std::thread
管理的线程仍然会引用它之前引用的对象。
所以,如果你想安全地move/swap一个C
,使用pimpl-idiom:
仅保护指向线程可能访问的资源的指针,并将该指针指向它。
在您的情况下,这意味着:
移动running_
:
struct inner {
std::atomic<bool> running;
};
unique_ptr<inner> data_ = new inner;
传递指向的数据:
auto data = &*data_;
thread_ = std::thread([data]() {
data->running = true;
while (data->running) {
...
}
});
(也可选择移动未被线程访问的数据。)
此外,即使您没有询问,您的 running
也必须是 std::atomic<bool>
,这样检查才有效。
我有一个 class,它有一个 std::thread
成员变量,它运行一个依赖于其他成员变量的 lambda 函数。
举个例子:
struct C {
C() {
thread_ = std::thread([this]() {
running_ = true;
while (running_) {
...
}
});
}
C(C&& rv) {
swap(rv);
}
void swap(C& rhs) {
std::swap(thread_, rhs.thread_); // step 1
std::swap(running_, rhs.running_); // step 2
}
std::thread thread_;
bool running_;
};
int main() {
C c;
C c2 = move(c); // Is c safely moved to c2?
}
- 移动此类物体的安全方法是什么?
- 移动操作后要指向哪个对象
[this]
。 - 在
step 1
之后step 2
之前,在 lambda 的 while 循环中访问了哪个对象的running_
?
虽然 std::thread
当然是可移动的,但这样做并不会神奇地修改任何引用它的指针,或者它包含的对象,如果有的话。
因此,即使在您移动 C
之后,包含的 std::thread
管理的线程仍然会引用它之前引用的对象。
所以,如果你想安全地move/swap一个C
,使用pimpl-idiom:
仅保护指向线程可能访问的资源的指针,并将该指针指向它。
在您的情况下,这意味着:
移动
running_
:struct inner { std::atomic<bool> running; }; unique_ptr<inner> data_ = new inner;
传递指向的数据:
auto data = &*data_; thread_ = std::thread([data]() { data->running = true; while (data->running) { ... } });
(也可选择移动未被线程访问的数据。)
此外,即使您没有询问,您的 running
也必须是 std::atomic<bool>
,这样检查才有效。