C++ 之 CreateThread 與beginThreadex用法具體示例解析 多執行緒 (三)
首先在此感謝 MoreWindows 秒殺多執行緒面試題系列讓我成長和學習!
在此再一次真心的感謝!
1 CreateThread示例
#include <iostream> #include <Windows.h> using namespace std; DWORD WINAPI threadone(LPVOID lpParamter) { cout<<"執行緒1執行" <<endl; return 0; } DWORD WINAPI threadtwo(LPVOID lpParamter) { cout<<"執行緒2執行"<<endl; return 0; } int main() { while (1) { HANDLE haddle = CreateThread(NULL, 0, threadone, NULL, 0, NULL); if (NULL == haddle) { cout<<"執行緒建立失敗:!" <<endl; } WaitForSingleObject(haddle, 50000); HANDLE handle1 = CreateThread(NULL, 0, threadtwo, NULL, 0, NULL); if (NULL == handle1) { cout<<"執行緒建立失敗!"<<endl; } WaitForSingleObject(haddle, 5000); } system("pause"); return 0; }
執行效果:
#include <windows.h> #include <process.h> #include <iostream> using namespace std; unsigned Counter; unsigned __stdcall SecondThreadFunc( PVOID pArguments ) { printf( "In second thread...\n" ); while ( Counter < 1000000 ) Counter++; _endthreadex( 0 ); return 0; } int main() { HANDLE hThread; unsigned threadID; // Create the second thread. hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID ); WaitForSingleObject( hThread, INFINITE ); printf( "Counter should be 1000000; it is-> %d\n", Counter ); cout<<threadID<<endl; // Destroy the thread object. CloseHandle( hThread ); system("pause"); }
執行效果:
3 下篇將要使用的函式說明
使用者模式的執行緒同步機制效率高,如果需要考慮執行緒同步問題,應該首先考慮使用者模式的執行緒同步方法。
但是,使用者模式的執行緒同步有限制,對於多個程序之間的執行緒同步,使用者模式的執行緒同步方法無能為力。這時,只能考慮使用核心模式。
Windows提供了許多核心物件來實現執行緒的同步。對於執行緒同步而言,這些核心物件有兩個非常重要的狀態:“已通知”狀態,“未通知”狀態(也有翻譯為:受信狀態,未受信狀態)。Windows提供了幾種核心物件可以處於已通知狀態和未通知狀態:程序、執行緒、作業、檔案、控制檯輸入/輸出/錯誤流、事件、等待定時器、訊號量、互斥物件。
你可以通知一個核心物件,使之處於“已通知狀態”,然後讓其他等待在該核心物件上的執行緒繼續執行。你可以使用Windows提供的API函式,等待函式來等待某一個或某些核心物件變為已通知狀態。
你可以使用WaitForSingleObject函式來等待一個核心物件變為已通知狀態:
DWORD WaitForSingleObject(
HANDLE hObject, //指明一個核心物件的控制代碼
DWORD dwMilliseconds); //等待時間
該函式需要傳遞一個核心物件控制代碼,該控制代碼標識一個核心物件,如果該核心物件處於未通知狀態,則該函式導致執行緒進入阻塞狀態;如果該核心物件處於已通知狀態,則該函式立即返回WAIT_OBJECT_0。第二個引數指明瞭需要等待的時間(毫秒),可以傳遞INFINITE指明要無限期等待下去。如果等待超時,該函式返回WAIT_TIMEOUT。如果該函式失敗,返回WAIT_FAILED。可以通過下面的程式碼來判斷:
DWORD dw = WaitForSingleObject(hProcess, 5000); //等待一個程序結束
switch (dw)
{
case WAIT_OBJECT_0:
// hProcess所代表的程序在5秒內結束
break;
case WAIT_TIMEOUT:
// 等待時間超過5秒
break;
case WAIT_FAILED:
// 函式呼叫失敗,比如傳遞了一個無效的控制代碼
break;
}
還可以使用WaitForMulitpleObjects函式來等待多個核心物件變為已通知狀態:
DWORD WaitForMultipleObjects(
DWORD dwCount, //等待的核心物件個數
CONST HANDLE* phObjects, //一個存放被等待的核心物件控制代碼的陣列
BOOL bWaitAll, //是否等到所有核心物件為已通知狀態後才返回
DWORD dwMilliseconds); //等待時間
該函式的第一個引數指明等待的核心物件的個數,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一個值。phObjects引數是一個存放等待的核心物件控制代碼的陣列。bWaitAll引數如果為TRUE,則只有當等待的所有核心物件為已通知狀態時函式才返回,如果為FALSE,則只要一個核心物件為已通知狀態,則該函式返回。第四個引數和WaitForSingleObject中的dwMilliseconds引數類似。
該函式失敗,返回WAIT_FAILED;如果超時,返回WAIT_TIMEOUT;如果bWaitAll引數為TRUE,函式成功則返回WAIT_OBJECT_0,如果bWaitAll為FALSE,函式成功則返回值指明是哪個核心物件收到通知。
可以如下使用該函式:
HANDLE h[3]; //控制代碼陣列
//三個程序控制代碼
h[0] = hProcess1;
h[1] = hProcess2;
h[2] = hProcess3;
DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); //等待3個程序結束
switch (dw)
{
case WAIT_FAILED:
// 函式呼叫失敗
break;
case WAIT_TIMEOUT:
// 超時
break;
case
WAIT_OBJECT_0 + 0:
// h[0](hProcess1)所代表的程序結束
break;
case
WAIT_OBJECT_0 + 1:
// h[1](hProcess2)所代表的程序結束
break;
case
WAIT_OBJECT_0 + 2:
// h[2](hProcess3)所代表的程序結束
break;
}
你也可以同時通知一個核心物件,同時等待另一個核心物件,這兩個操作以原子的方式進行:
DWORD SignalObjectAndWait(
HANDLE hObjectToSignal, //通知的核心物件
HANDLE hObjectToWaitOn, //等待的核心物件
DWORD dwMilliseconds, //等待的時間
BOOL bAlertable); //與IO完成埠有關的引數,暫不討論
該函式在內部使得hObjectToSignal引數所指明的核心物件變成已通知狀態,同時等待hObjectToWaitOn引數所代表的核心物件。dwMilliseconds引數的用法與WaitForSingleObject函式類似。
該函式返回如下:WAIT_OBJECT_0,WAIT_TIMEOUT,WAIT_FAILED,WAIT_IO_COMPLETION。
等你需要通知一個互斥核心物件並等待一個事件核心物件的時候,可以這麼寫:
ReleaseMutex(hMutex);
WaitForSingleObject(hEvent, INFINITE);
可是,這樣的程式碼不是以原子的方式來操縱這兩個核心物件。因此,可以更改如下:
SignalObjectAndWait(hMutex, hEvent, INFINITE, FALSE);
期待將持續更新(將說明CRITICAL_SECTION的引數含義和臨界區的聯絡)!
如果覺得本文對您有幫助,請點選‘頂’支援一下,您的支援是我寫作最大的動力,謝謝。
注:以上在VS2010 下執行編譯!