当所有其他线程在主线程之前完成时,为什么.join仍然是必需的?

时间:2014-04-07 06:38:59

标签: c++ multithreading

学习C ++多线程 在我的示例中,线程helper1helper2main线程完成之前已完成执行。但是,程序崩溃了。我特别指出了.join()语句,看看程序如何表现,期待没有错误,因为main()在其他两个线程完成后调用std::terminate

void foo()
{
    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "t1\n";
}

void bar()
{
    // simulate expensive operation
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "t2\n";
}

int main()
{

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

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


    std::this_thread::sleep_for(std::chrono::seconds(10));

    std::cout << "waiting for helpers to finish..." << std::endl;
    //helper1.join();
    //helper2.join();

    std::cout << "done!\n";
}

4 个答案:

答案 0 :(得分:6)

我说你的问题没有意义,因为它是基于错误的假设。了解 线程已完成的唯一方法是线程的join()返回。在join()返回之前,并不是&#34;线程已经完成&#34;。可能确实线程执行中的某些语句已经完成(例如,打印消息,或者更好,写入原子变量),但是线程函数本身的完成不是可测量的以任何其他方式加入。

所以 none 线程&#34;已完成&#34;直到你加入他们。

答案 1 :(得分:4)

如果关联线程仍可加入,std::~thread会调用terminate

  

30.3.1.3 thread destructor [thread.thread.destr]

~thread();
     

如果joinable(),请致电std::terminate()。否则,没有任何影响。 [   注意:隐式分离或连接其析构函数中的joinable()线程可能导致难以调试正确性(对于分离)或性能(对于连接)仅在引发异常时遇到的错误。因此,程序员必须确保在线程仍可连接时永远不会执行析构函数。 - 后注]

需要致电.detach().join()。除此之外,由于您无法确定操作系统如何安排线程,您最终可能会以任何方式中断线程,因此最好从一开始就使用.join()

答案 2 :(得分:4)

基于reference,必须在调用析构函数时加入或分离底层线程。退出main时会调用析构函数,并可能假定已调用joindetach

代码也不应该崩溃,只要在构造helper1helper2之后的某个地方有以下两行。

helper1.detach()
helper2.detach()

答案 3 :(得分:3)

CPU可以按任意顺序安排三个线程(main / thread1 / thread2)。可能会发生main没有时间运行并且线程退出的情况。因此,您需要在join中保持main以处理此案例。除非您使用RTOS

,否则线程的调度是不可预测的