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

时间:2017-03-09 10:15:28

标签: 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();
}

我正在以下列方式使用它:

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;
}

这是输出:

  

线程#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;
}

仍然可以加入线程。我查了joinable引用,他们说:

  

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

因此,这与WaitForSingleObject无关。问题是为什么一个线程在完成执行后仍然被认为是joinable()

我已经看到这个question让我更加困惑,因为它表明当线程完成执行时,即使在调用joinable()join()之前,它也不是detach()

2 个答案:

答案 0 :(得分:5)

  

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

因为你可能想编写join()的代码。如果t.joinable()在终止时自动变为假,则无法安全地致电t.join()。你可以这样写:

if (t.joinable()) {
    t.join();
}

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

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

答案 1 :(得分:4)

joinable并不意味着still_running,可加入只是意味着线程对象不是&#34;空&#34; (作为默认构造或移动的结果)并且与实际的OS执行线程相关联。

如果线程为空,则意味着没有任何东西可以加入,因此,线程不是&#34;可加入&#34;。

如果线程不为空​​,则可以使当前线程等待它,因此它是&#34;可加入&#34;。