看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《rosemary0401 (rosemary0401)》之銘言: : 仿照網路上找到的範例,練習寫thread : 程式碼如下: : #include <iostream> : #include <windows.h> : #include <process.h> : #define THREAD_COUNT 2 : using namespace std; : int g_num = 0; : void ThreadVariable1(void* argu) : { : Sleep(3000); : g_num = 100; : _endthread(); : } : void ThreadVariable2(void* argu) : { : Sleep(3000); : g_num = 50; : _endthread(); : } : void main() : { : HANDLE threadArray[THREAD_COUNT]; : threadArray[0] = (HANDLE) _beginthread(ThreadVariable1, 0, NULL); : threadArray[1] = (HANDLE) _beginthread(ThreadVariable2, 0, NULL); : WaitForMultipleObjects(THREAD_COUNT, threadArray, TRUE, INFINITE); : printf("%d\n", g_num); : CloseHandle(threadArray[0]); : CloseHandle(threadArray[1]); : cin.get(); : } : 編譯會過,但是執行會出現錯誤如下: : First-chance exception at 0x772d5e4f in simpleThreadTest2.exe: 0xC0000008: An : invalid handle was specified. : 為什麼呢? 把你那兩個 _endthread(); 改成 _endthreadex(0); 就可以了。 這個問題很經典,在《Programming Applications for Microsoft Windows》有提到。 他說在 C/C++ 程式內使用 CreateThread / CloseThread 是應該的,這個很多人都知道 了,因為 C/C++ 有個叫 ptd 的東西。 因為這個關係,所以微軟的 CRT 裡面有個 CreateThread 的包裝,就是 _beginthreadex / _endthreadex 系列,他們有解決 ptd 的問題, 他的參數跟回傳值跟 CreateThread 一模一樣,目的就是設計出來讓你取代用的。 所以你不用 _beginthreadex(...) 就是不應該。 那麼 _beginthread / _endthread 純粹是一個簡化用的版本,你可以發現參數比較少, 比較容易使用,但這套函數問題很多,也應該盡量避免使用。 當你使用 ex 版建立執行緒時,只要執行緒函數執行完畢,就會自動調用 _endthreadex; 相對的,你建立執行緒時用了 _beginthread,則就算你不去明確調用 _endthread,在 執行緒函數執行完時,還是會自動調用 _endthread。 而 _endthread 有個錯誤的行為,他會先從 ptd 把這個執行緒物件的 Handle 抓出來, 然後『裝會』的替你執行 CloseHandle 動作,把這個執行緒的控制代碼關掉,接著才再 執行 Win32 API 的 ExitThread 作為結束。 因為 _endthread 幫你把控制代碼關了,所以你在那邊 WaitMultipleObjects 等完, 你的執行緒不只關掉,其控制代碼也被關掉了,所以你做了 CloseHandle 時會有錯誤, 說是無效的 Handle。 只要你一開始就用 _beginthreadex 去建立就不會有這個問題。 或者雖然用 _beginthread 去建,但結束執行緒時,改成明確調用 _endthreadex 來略 過 _endthread 來避免 (不推薦)。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 124.8.136.102 ※ 編輯: purpose 來自: 124.8.136.102 (11/29 15:34)
rosemary0401:原來如此 THANKS! 11/29 15:46