WIN32線程控制主要實現線程的創建、終止、掛起和恢復等操作,這些操作都依賴于WIN32提供的一組API和具體編譯器的C運行時庫函數。
WIN32線程控制主要實現線程的創建、終止、掛起和恢復等操作,這些操作都依賴于WIN32提供的一組API和具體編譯器的C運行時庫函數。
1.線程函數
在啟動一個線程之前,必須為線程編寫一個全局的線程函數,這個線程函數接受一個32位的LPVOID作為參數,返回一個UINT,線程函數的結構為:
UINT ThreadFunction(LPVOID pParam) { //線程處理代碼 return0; } |
在線程處理代碼部分通常包括一個死循環,該循環中先等待某事情的發生,再處理相關的工作:
while(1) { WaitForSingleObject(…,…);//或WaitForMultipleObjects(…) //Do something } |
一般來說,C++的類成員函數不能作為線程函數。這是因為在類中定義的成員函數,編譯器會給其加上this指針。請看下列程序:
#include "windows.h" #include <process.h> class ExampleTask { public: void taskmain(LPVOID param); void StartTask(); }; void ExampleTask::taskmain(LPVOID param) {}
void ExampleTask::StartTask() { _beginthread(taskmain,0,NULL); }
int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } |
程序編譯時出現如下錯誤:
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)' None of the functions with this name in scope match the target type |
再看下列程序:
#include "windows.h" #include <process.h> class ExampleTask { public: void taskmain(LPVOID param); };
void ExampleTask::taskmain(LPVOID param) {}
int main(int argc, char* argv[]) { ExampleTask realTimeTask; _beginthread(ExampleTask::taskmain,0,NULL); return 0; } |
程序編譯時會出錯:
error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)' None of the functions with this name in scope match the target type |
如果一定要以類成員函數作為線程函數,通常有如下解決方案:
(1)將該成員函數聲明為static類型,去掉this指針;
我們將上述二個程序改變為:
#include "windows.h" #include <process.h> class ExampleTask { public: void static taskmain(LPVOID param); void StartTask(); };
void ExampleTask::taskmain(LPVOID param) {}
void ExampleTask::StartTask() { _beginthread(taskmain,0,NULL); }
int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } 和 #include "windows.h" #include <process.h> class ExampleTask { public: void static taskmain(LPVOID param); };
void ExampleTask::taskmain(LPVOID param) {}
int main(int argc, char* argv[]) { _beginthread(ExampleTask::taskmain,0,NULL); return 0; } |
均編譯通過。
將成員函數聲明為靜態雖然可以解決作為線程函數的問題,但是它帶來了新的問題,那就是static成員函數只能訪問static成員。解決此問題的一種途徑是可以在調用類靜態成員函數(線程函數)時將this指針作為參數傳入,并在改線程函數中用強制類型轉換將this轉換成指向該類的指針,通過該指針訪問非靜態成員。
(2)不定義類成員函數為線程函數,而將線程函數定義為類的友元函數。這樣,線程函數也可以有類成員函數同等的權限;
我們將程序修改為:
#include "windows.h" #include <process.h> class ExampleTask { public: friend void taskmain(LPVOID param); void StartTask(); };
void taskmain(LPVOID param) { ExampleTask * pTaskMain = (ExampleTask *) param; //通過pTaskMain指針引用 }
void ExampleTask::StartTask() { _beginthread(taskmain,0,this); } int main(int argc, char* argv[]) { ExampleTask realTimeTask; realTimeTask.StartTask(); return 0; } |
(3)可以對非靜態成員函數實現回調,并訪問非靜態成員,此法涉及到一些高級技巧,在此不再詳述。