推 rosemary0401:原來如此 THANKS! 11/29 15:46
※ 引述《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)