C++线程在完成执行后仍然是`joinable()`吗?

Eve*_*one 4 c++ multithreading lifetime

我有以下功能:

void threadProc(){
    for (int i = 0; i < 5; ++i) {
        std::cout << "\n  thread #" << std::this_thread::get_id() << " says hi";
    }
    std::cout << "\n  Finished executing thread #" << std::this_thread::get_id();
}
Run Code Online (Sandbox Code Playgroud)

我使用它的方式如下:

int main(){
    try {
        std::thread t1(threadProc);
        t1.join();

        std::thread t2(threadProc);
        HANDLE handle = t2.native_handle(); 
        WaitForSingleObject(handle, INFINITE);
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
        std::cout << "\n  thread t2 is joinable: " << std::boolalpha << t2.joinable() << "\n\n";
    }
    catch (std::exception& ex){
        std::cout << "\n\n  " << ex.what() << "\n\n";
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

线程#21300说嗨

线程#21300说嗨

线程#21300说嗨

线程#21300说嗨

线程#21300说嗨

完成执行线程#21300

线程#2136说嗨

线程#2136说嗨

线程#2136说嗨

线程#2136说嗨

线程#2136说嗨

完成执行线程#2136

线程t2是可连接的:true

然后当try块超出范围时崩溃因为abort()被调用t2.

我的问题是,为什么t2仍然joinable()即使它的时候threadProc结束?为什么没有完成处理?

而且,我正在使用WaitForSingleObject以确保我等到t2完成处理.我还添加了5秒等待,以确保它花费时间来完成其处理.然而,有些事情仍未完成.

我知道我可以使用t2.join(),t2.detach()但我为什么要这样做?t2已完成处理(我认为).


编辑:我尝试了以下代码:

int main() {
    try {
        std::thread t1([]() {std::cout << "\n\n  Hi from thread #" << std::this_thread::get_id(); });
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    catch (std::exception& ex) {
        std::cout << "\n\n  " << ex.what() << "\n\n";
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

而且线程仍然可以连接.我抬头看了joinable参考文献,他们说:

已完成执行代码但尚未加入的线程仍被视为活动执行线程,因此可以连接.

所以这与此无关WaitForSingleObject.问题是为什么joinable()在完成执行后仍然会考虑一个线程?

我已经看到了这个问题,这让我感到困惑,甚至更多,因为它指出,当线程执行完毕后,它不是joinable()甚至称之前join()detach().

Dav*_*aim 9

joinable 并不意味着 still_running,joinable 只是意味着线程对象不是“空的”(作为默认构造或移动的结果)并且与真正的操作系统执行线程相关联。

如果线程为空,则意味着没有要加入的内容,因此,该线程不可“加入”。

如果线程不为空​​,您可以让当前线程等待它,因此它是“可加入的”。

  • 它没有。如果一个线程对象是可连接的,那么它变成不可连接的唯一方法(假设你的代码中没有其他任何东西触发未定义的行为)是从它移动,分配给它,或者显式调用 join() 或 detach()。如果某件事让您认为某个线程可能会自发地变得不可连接,那么您的来源要么是错误的,要么是您误解了它。 (2认同)

Sol*_*low 5

问题是为什么线程在完成执行后仍被认为是joinable()?

因为你可能想编写join()的代码.如果t.joinable()在终止时自动变为假,那么就没有安全的方式来打电话t.join().你可以这样写:

if (t.joinable()) {
    t.join();
}
Run Code Online (Sandbox Code Playgroud)

但是,如果线程在t.joinable()返回之后终止true,但在调用者能够完成t.join()调用之前,仍然会抛出异常.

让线程保持可连接直到它实际上是join()ed是更简单的行为来描述,并且编写正确使用它的代码更容易.