线程连接问题

Thread joining issue

本文关键字:问题 连接 线程      更新时间:2023-10-16

我读了一些关于线程的手册,我觉得它们显示的代码不安全:

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

我认为这个代码不是绝对安全的。如果我没有弄错的话,当控制到达标记为#1#2的行时,不能保证helper1helper2已经处于可连接状态。线程可能仍然无法启动,并且此时没有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

如果std::thread包含未经join编辑或detatch编辑的线程状态,则CCD_6为joinable

std::thread通过非默认构造或从另一个std::thread将一个CCD11插入其中来获得线程状态。move从发出时丢失。

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

有一个问题是,如果代码抛出以上内容,您将无法执行joindetatch,从而导致程序关闭时出现坏消息。为了避免这种情况,请始终将std::thread包装在RAII包装中,或者只使用返回voidstd::async,并以类似的方式包装生成的std::future(因为标准规定它在dtor中阻塞,但微软的实现没有,所以你不能相信它是否会阻塞)。

您对线程的感知过于复杂。join用于安全地加入线程。只需使用:

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

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

后置条件:get_id() != id()。CCD_ 23表示新启动的线程。

joinable()的定义是

返回:get_id() != id()

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