线程加入问题

时间:2013-11-25 11:29:08

标签: c++ multithreading c++11 thread-safety

我正在阅读关于线程的一些manuals,我开始认为他们展示的代码并不安全:

std::cout << "starting first helper...\n";
std::thread helper1(foo);

std::cout << "starting second helper...\n";
std::thread helper2(bar);

std::cout << "waiting for helpers to finish..." << std::endl;
helper1.join();   // #1 NOT SAFE
helper2.join();   // #2 NOT SAFE

我相信这段代码不是绝对安全的。如果我没有误会,当控件到达标记为helper1helper2的行时,无法保证#1#2已处于可加入状态。线程仍然无法启动,此时没有任何ID。这将导致从std::thread::join()

抛出未捕获的异常

我认为以下代码可以解决问题。我是对的吗?

std::cout << "starting first helper...\n";
std::thread helper1(foo);

std::cout << "starting second helper...\n";
std::thread helper2(bar);

std::cout << "waiting for helpers to finish..." << std::endl;
while ( helper1.joinable() == false ) { }
helper1.join();   // #1 SAFE
while ( helper2.joinable() == false ) { }
helper2.join();   // #2 SAFE

3 个答案:

答案 0 :(得分:5)

如果std::thread包含尚未joinablejoin编辑的主题状态,则detatchstd::thread

move通过非默认构造获得线程状态,或者从另一个std::thread加入一个movejoin编辑时会丢失它。

构造完成后获得线程状态没有延迟。当线程函数完成时它不会消失。所以没有那个问题。

如果代码抛出上面,则会出现问题,您将无法detatchstd::thread,导致程序关闭时出现坏消息。始终将std::async包装在RAII包装器中以避免这种情况,或者只使用返回void的{​​{1}}并同样包装生成的std::future(因为标准表示它在dtor中阻塞,但微软实现没有,所以你不能相信它是否会。)

答案 1 :(得分:3)

您以过于复杂的方式感知线程。 join可以安全加入一个帖子。只需使用:

std::thread my_thread(my_main);
my_thread.join();

答案 2 :(得分:2)

std::thread::thread(F&& f, Args&&... args)构造函数具有此后置条件:

  

后置条件: get_id() != id()*this代表新启动的主题。

joinable()的定义是

  

返回: get_id() != id()

因此构造函数的后置条件是对象是可连接的,并且后置条件在构造函数完成后立即应用。操作系统是否实际启动了线程无关紧要,thread对象仍然知道新线程的ID,并且仍然可以等待它完成并加入它。