在类构造函数线程中启动 std::thread 是不是安全?
Posted
技术标签:
【中文标题】在类构造函数线程中启动 std::thread 是不是安全?【英文标题】:Is starting an std::thread in a class constructor thread safe?在类构造函数线程中启动 std::thread 是否安全? 【发布时间】:2019-12-01 20:53:31 【问题描述】:所以我有一个类似这样的代码(C++11):
class Foo
private:
std::vector<int> vec;
int val;
std::thread Foo_thread;
public:
Foo();
void StartLoop();
void WaitTermination() this->Foo_thread.join();
void AddToVec(int dummy) vec.push_back(dummy);
void setter(int val) this->val = val;
;
void Foo::StartLoop()
while (true)
// some code . . .
this->vec.push_back(something);
Foo::Foo()
this->Foo_thread = std::thread(&Foo:SartLoop, this);
int main()
Foo* f = new Foo;
f->WaitTermination();
如果我理解得很好,f 指针和 Foo 实例位于主线程中。在构造函数this->Foo_thread = std::thread(&Foo:SartLoop, this);
中,Foo实例的地址被传递给std::thread,所以这个线程可以访问这个对象的成员,例如在Foo::StartLoop()中:this->vec.push_back。
但是,Foo 类有一个公共的 AddToVec(),所以我可以在 main() 中写:
int main()
Foo* f = new Foo;
f->AddToVec(78); // at this point, we modify the private vec member, both from the main thread and in the std::thread, if I undersand well
f->setter(67); // same problem, however it's easier to declare val as std::atomic<int>, but the above one is really problematic
f->WaitTermination();
我的问题是,我理解得好吗?如何修复此代码?我想保留constructor-creates-thread机制。
谢谢
【问题讨论】:
本质上,如果多个线程修改数据,则需要使用同步原语,如std::mutex
在 main() 中,如果我不做 f->AddToVec(78); f->setter(67);来电,我的代码没问题?
好吧,你拼错了“SartLoop”,一方面:(
多线程很难。您需要阅读C++ Concurrency in Action 之类的书籍或学习一些课程,以至少了解基本原理。否则,您将获得损坏的数据或死锁。
【参考方案1】:
导致数据竞争调用 f->AddToVec(78); f->setter(67);主要。没有它们,使用 this
指针访问正在构建的对象是安全的,因为它不是 UB 并且语言标准并不禁止这样做。
但在实践中,不建议使用正在构建的this
,有经验的开发人员经常会尽量避免,因为它会随着代码的发展而导致问题:
【讨论】:
以上是关于在类构造函数线程中启动 std::thread 是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章