[英]C++11: What happens if you don't call join() for std::thread
下面給出:
void test()
{
std::chrono::seconds dura( 20 );
std::this_thread::sleep_for( dura );
}
int main()
{
std::thread th1(test);
std::chrono::seconds dura( 5 );
std::this_thread::sleep_for( dura );
return 0;
}
main
將在 5 秒后退出,仍在執行的th1
會發生什么?
即使您在main
定義的th1
線程對象超出范圍並被銷毀,它是否會繼續執行直到完成?
th1
是否只是在它完成執行后就坐在那里,或者在程序終止時以某種方式被清除?
如果線程是在函數中創建的,而不是在main
創建的 - 線程是否會一直存在直到程序終止或函數超出范圍?
如果您想要線程上的某種類型的超時行為,那么簡單地不為線程調用join
是否安全?
如果在調用析構函數時您沒有分離或加入線程,它將調用std::terminate
,我們可以通過轉到C++11 標准草案來看到這一點,我們看到第30.3.1.3
節線程析構函數說:
如果 joinable(),則調用 std::terminate()。 否則,沒有任何影響。 [ 注意:在其析構函數中隱式分離或加入 joinable() 線程可能會導致難以調試正確性(對於分離)或性能(對於連接)錯誤,只有在引發異常時才會遇到。 因此,程序員必須確保在線程仍可連接時永遠不會執行析構函數。 ——尾注]
至於這種行為的基本原理,我們可以 使用 std::thread在(Not) 中找到一個很好的總結
為什么可連接線程的析構函數必須調用 std::terminate? 畢竟,析構函數可以加入子線程,也可以與子線程分離,或者取消線程。 簡而言之,您不能加入析構函數,因為如果 f2 拋出,這將導致意外(未在代碼中明確指出)程序凍結。
一個例子如下,還說:
您不能分離,因為這會導致主線程離開啟動子線程的作用域,而子線程繼續運行並保留對已經消失的作用域的引用的情況。
該文章引用了N2802:請求重新考慮線程對象的 detach-on-destruction,這是反對先前提議的論點,如果可連接,則在破壞時分離,並指出兩種選擇之一是 join,這可能導致死鎖另一種選擇是我們今天所擁有的,如果可連接,則std::terminate
銷毀。
std::thread::~thread()
如果 *this 有關聯線程(
joinable() == true
),則調用std::terminate()
來源: http : //en.cppreference.com/w/cpp/thread/thread/~thread
這意味着像這樣的程序根本不是格式良好或安全的。
但是請注意,在這種情況下, boost::thread::~thread()
調用detach()
。 (正如用戶dyp在評論中所述,此行為在最近的版本中已被棄用)
您始終可以使用 RAII 解決此問題。 只需將您的線程包裝在另一個類中,這將具有所需的銷毀行為。
在 C++11 中,當新創建的線程超出范圍(我們的 dtor 被調用)時,您必須明確指定“會發生什么”。 有時,當我們確定主線程正在繼續並且我們的線程充當“管道”時,“分離()”它們是安全的; 有時當我們等待我們的 WORKER 線程完成它們的操作時,我們“加入()”它們。
正如這所說,程序員必須確保在線程仍可連接時永遠不會執行析構函數。
指定您的多線程策略。 在這個例子中, std::terminate()
被調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.