簡體   English   中英

C++11:如果不為 std::thread 調用 join() 會發生什么

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM