8

在某些時候,我記得讀到直到main()的第一行才能安全地創建線程,因爲編譯器會插入特殊的代碼來在靜態初始化時間內運行線程工作。所以如果你有一個全局對象在構建時創建一個線程,你的程序可能會崩潰。但是現在我找不到原文,我很好奇這個限制有多嚴格 - 這是標準嚴格遵守的嗎?在大多數編譯器上它是真的嗎?它會在C++ 0x中保持真實嗎?一個符合標準的編譯器是否有可能自己創建靜態初始化程序多線程? (例如,檢測到兩個全局對象不相互接觸,並在單獨的線程上初始化它們以加速程序啓動)在靜態初始化期間可以安全地創建線程嗎?

編輯:爲了澄清,我試圖至少了解實現是否真的顯着不同在這方面,或者如果這是僞標準的東西。例如,在技術上,該標準允許對屬於不同訪問說明符(public/protected /等)的成員進行混洗。但沒有編譯器我知道實際上是否這樣做。

+0

「這是嚴格按照標準真正的」 - C++ 03標準對於線程主題沒有什麼可說的。當前行爲所關注的地方是POSIX(它當然是* a *標準,而不是*標準),MSDN,Boost或其他針對編譯器,平臺和線程API的特定於實現的文檔使用。 – 2009-09-18 15:25:31

回答

6

你說的不是嚴格的語言,而是C運行時間庫(CRT)。
首先,如果您在Windows上使用本機調用(如CreateThread())創建線程,則可以在任何需要的位置執行此操作,因爲它可以在不干涉CRT的情況下直接進入操作系統。
您通常使用的其他選項是使用_beginthread(),它是CRT的一部分。使用_beginthread()有一些優點,例如具有線程安全的errno。 Read more about this here。如果要使用_beginthread()創建線程,則可能會出現一些問題,因爲_beginthread()所需的初始化可能不適用。

這涉及到一個更爲普遍的問題,即在main()之前發生了什麼以及按什麼順序。基本上你有程序的入口點功能,在使用Visual Studio處理main()之前需要處理所有需要發生的事情,你可以看看CRT中的這段代碼,並找出自己究竟發生了什麼。最簡單的方法是停止代碼中的斷點,然後查看堆棧幀main()

+0

謝謝,這給了我一些有關使用MSVC的Windows情況的想法。我仍然對其他平臺感到好奇,它並沒有真正回答它是否在Windows上安全(_beginthread()實際上是否依賴於任何可能還沒有發生的初始化?)。 – 2009-09-18 18:22:50

+0

我希望我也知道這一點。文檔似乎沒有提及它。 – shoosh 2009-09-18 19:40:15

2

底層問題是Windows對DllMain中可以執行和不能執行的操作的限制。特別是,你不應該在DllMain中創建線程。靜態初始化通常發生在DllMain中。然後在邏輯上遵循靜態初始化過程中不能創建線程。

+1

但是請注意:'在進程啓動和DLL初始化例程期間,可以創建新線程,但是直到http://msdn.microsoft的進程完成DLL初始化纔開始執行。com/en-us/library/ms682453%28v = VS.85%29.aspx – 2011-07-16 21:29:49

+0

公平點,沒有見過。請注意,該註釋特別適用於'CreateThread',但_beginthreadex沒有這個例外。 – MSalters 2011-07-18 08:01:53

0

據我所知,通過閱讀C++ 0x/1x草案,在main()之前啓動一個線程是很好的,但仍然受到靜態初始化的正常陷阱。一致性實現必須確保在任何靜態或線程構造函數執行之前執行線程初始化的代碼。

相關問題