C++中的thread對象通常來說表達了執行的線程(thread of execution),這是一個OS或者平台的概念。
當thread::join()函數被調用后,調用它的線程會被block,直到線程的執行被完成。基本上,這是一種可以用來知道一個線程已結束的機制。當thread::join()返回時,OS的執行的線程已經完成,C++線程對象可以被銷毀。
當thread::detach()函數被調用后,執行的線程從線程對象中被分離,已不再被一個線程對象所表達--這是兩個獨立的事情。C++線程對象可以被銷毀,同時OS執行的線程可以繼續。如果程序想要知道執行的線程何時結束,就需要一些其它的機制。join()函數在那個thread對象上不能再被調用,因為它已經不再和一個執行的線程相關聯。
去銷毀一個仍然可以“joinable”的C++線程對象會被認為是一種錯誤。為了銷毀一個C++線程對象,約么join()函數需要被調用(並結束),要么detach()函數被調用。如果一個C++線程對象當銷毀時仍然可以被join,異常會被拋出。
C++線程對象不被表達為執行的線程的其它的情況(也就是unjoinable):
- 默認構造的線程對象不表達為執行的線程,所以是unjoinable。
- 被移開的線程將不表達為執行的線程,所以是unjoinable。
在std::thread的析構函數中,std::terminate會被調用如果:
- 線程沒有被Joined(用t.join())
- 線程也沒有被detached(用t.detach())
因此,你應該在執行流程到析構函數前總是要么join,要么detach一個線程。
當一個程序終止時(比如main返回),剩下的在后台的detached線程執行不會再等待;相反它們的執行會被掛起並且它們的本地線程對象會被銷毀。
關鍵地,這意味着這些線程的棧不是完好無損的,因此一些析構函數不會被執行。
依賴於這些行為,一些析構函數假象會被承擔,這可能是一種壞情形,好像程序已經Crash或者已經被kill。希望OS會釋放加在這些文件上的鎖。Depending on the actions those destructors were supposed to undertake, this might be as bad a situation as if the program had crashed or had been killed. Hopefully the OS will release the locks on files, etc... but you could have corrupted shared memory, half-written files, and the like.
所以,你應該使用join還是detached?
- 使用join
- 除非你需要更靈活並且想要獨立地提供一種同步機制來等待線程完成,在這種情況下你應該使用detach。使用detach會引發一些難以定位的問題,能不用就不用。