windows下多執行緒同步
阿新 • • 發佈:2019-01-28
互斥量(鎖)
適用範圍:可以跨程序同步,還可以用來保證程式只有一個互斥鎖例項執行(建立命名互斥量),也可以用來做執行緒間的同步
如果用於程序間同步,一個執行緒建立互斥量物件後,另一個程序只需要獲取互斥量就可以,可以用OpenMutex(MUTEX_ALL_ACCESS,FALSE,"TesthMutex")函式獲取
#include<Windows.h> #include<iostream> using namespace std; int money=0; HANDLE hMutex; //執行緒1回撥函式 //希望兩個執行緒把monery加到100,執行緒1休眠的時候讓執行緒2去處理 DWORD WINAPI ThreadFun1(LPVOID args) { while(true) { /* *檢測hHandle事件的訊號狀態函式詳細說明 *DWORD WINAPI WaitForSingleObject( __in HANDLE hHandle, __in DWORD dwMilliseconds ); *返回值:執行成功,返回值指示出引發函式返回的事件。它可能為以下值: WAIT_OBJECT_0 0x00000000 :指定的物件出有有訊號狀態 WAIT_TIMEOUT 0x00000102:等待超時 WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤程式碼 *引數說明: *hHandle 物件控制代碼,可以指定一系列的物件,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等 *dwMilliseconds]定時時間間隔,單位為milliseconds(毫秒).如果指定一個非零值,函式處於等待狀態直到hHandle標記的物件被觸發,或者時間到了\ 如果dwMilliseconds為0,物件沒有被觸發訊號,函式不會進入一個等待狀態,它總是立即返回。如果dwMilliseconds為INFINITE,物件被觸發訊號後,函式才會返回 */ //等待互斥物件的訊號,INFINITE表示一直等待,對之後的程式碼進行保護,有訊號立即返回 WaitForSingleObject(hMutex,INFINITE); if(money<100) { ++money; cout<<"thred1 money:"<<money<<endl; ReleaseMutex(hMutex);//釋放指定互斥物件的所有權,互斥物件變為已通知狀態,執行緒2就能獲取到互斥物件 } else { break; } } return 0; } //執行緒2回撥函式 DWORD WINAPI ThreadFun2(LPVOID args) { while(true) { WaitForSingleObject(hMutex,INFINITE); Sleep(1); if(money<100) { ++money; cout<<"thred2 money:"<<money<<endl; ReleaseMutex(hMutex); } else { break; } } return 0; } int main() { HANDLE Thread1,Thread2; /* 建立執行緒函式詳細說明 *HANDLE WINAPI CreateThread( __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in SIZE_T dwStackSize, __in LPTHREAD_START_ROUTINE lpStartAddress, __in_opt __deref __drv_aliasesMem LPVOID lpParameter, __in DWORD dwCreationFlags, __out_opt LPDWORD lpThreadId ); *返回值:函式成功,返回執行緒控制代碼;函式失敗返回false。若不想返回執行緒ID,設定值為NULL *引數說明: *lpThreadAttributes 執行緒安全性,使用預設安全性,一般預設null *dwStackSize 堆疊大小,0為預設大小 *lpStartAddress 執行緒要執行的函式指標,即入口函式 *lpParameter 執行緒引數 *dwCreationFlags 執行緒標記,如為0,則建立後立即執行 *lpThreadId LPDWORD為返回值型別,一般傳遞地址去接收執行緒的識別符號,一般設為null */ Thread1=CreateThread(NULL,0,ThreadFun1,NULL,0,NULL); if(Thread1==NULL) { cout<<"CreateThread1 fail"<<endl; } Thread2=CreateThread(NULL,0,ThreadFun2,NULL,0,NULL); if(Thread2==NULL) { cout<<"CreateThread2 fail"<<endl; } CloseHandle(Thread1);//關閉執行緒控制代碼,核心物件引用計數器減1,只有核心物件引用為0時才會釋放執行緒記憶體物件 CloseHandle(Thread2); /* 建立互斥物件函式詳細說明 *HANDLE WINAPI CreateMutexA( __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes, __in BOOL bInitialOwner, __in_opt LPCSTR lpName ); *返回值:如執行成功,就返回互斥體物件的控制代碼;零表示出錯。會設定GetLastError。如果返回的是一個有效控制代碼,但指定的名字已經存在,GetLastError也會設為ERROR_ALREADY_EXISTS, bInitialOwner的值將會被忽略。如果呼叫者限制了許可權,GetLastError將會返回ERROR_ACCESS_DENIED,這個時候應該使用OpenMutex函式。 *引數說明: *lpMutexAttributes 指向安全屬性的指標 *bInitialOwner 初始化互斥物件的所有者 *lpName 指向互斥物件名的指標,如果填寫了就算是建立了一個命名的互斥物件,只能有一個test程序執行 */ hMutex =CreateMutex(NULL,false,"test"); //建立命名互斥物件,且為有訊號狀態 if(hMutex) { if(ERROR_ALREADY_EXISTS==GetLastError()) { cout<<"已經有一個相同應用程式在執行!"<<endl; return 0; } } system("pause"); CloseHandle(hMutex); return 0; }
事件物件
適用範圍:多用於執行緒間的通訊,可以跨程序同步
#include<Windows.h> #include<iostream> using namespace std; int money=0; HANDLE hEvent;//定義事件控制代碼 DWORD WINAPI Thread1(LPVOID lpThreadParameter) { while(true) { WaitForSingleObject(hEvent,INFINITE);//當執行緒獲取到訊號時,作業系統會自動把事件物件設定為無訊號因為我CreateEvent函式第二個引數設定為自動的 Sleep(1); if(money<100) { ++money; cout<<"thred1 money:"<<money<<endl; /* *重置事件物件為有訊號 *BOOL SetEvent(HANDLE hEvent); *返回值:如果操作成功,則返回非零值,否則為0 *引數說明: *hEvent 設定控制代碼為有訊號 */ SetEvent(hEvent); } else { break; } } return 0; } DWORD WINAPI Thread2(LPVOID lpThreadParameter) { while(true) { WaitForSingleObject(hEvent,INFINITE); Sleep(1); if(money<100) { ++money; cout<<"thred2 money:"<<money<<endl; SetEvent(hEvent); } else { break; } } return 0; } int main() { HANDLE thred1,thred2; thred1=CreateThread(NULL,0,Thread1,NULL,0,NULL); if(thred1==NULL) { cout<<"CreateThread1 fail"<<endl; } thred2=CreateThread(NULL,0,Thread2,NULL,0,NULL); if(thred2==NULL) { cout<<"CreateThread1 fail"<<endl; } CloseHandle(thred1);//關閉執行緒控制代碼 CloseHandle(thred2); /* *建立事件物件 HANDLE WINAPI CreateEventA( __in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, __in BOOL bManualReset, __in BOOL bInitialState, __in_opt LPCSTR lpName ); *返回值:如果函式呼叫成功,函式返回事件物件的控制代碼。如果對於命名的物件,在函式呼叫前已經被建立,函式將返回存在的事件物件的控制代碼,而且在GetLastError函式中返回ERROR_ALREADY_EXISTS。 如果函式失敗,函式返回值為NULL,如果需要獲得詳細的錯誤資訊,需要呼叫GetLastError。 *引數說明: *lpEventAttributes 安全性,採用null預設安全性。 *bManualReset (TRUE)人工重置或(FALSE)自動重置事件物件為非訊號狀態,若設為人工重置,則當事件為有訊號狀態時,所有等待的執行緒都變為可排程執行緒。 *bInitialState 指定事件物件的初始化狀態,TRUE:初始為有訊號狀態。 *lpName 事件物件的名字,一般null匿名即可 */ hEvent=CreateEvent(NULL,false,true,NULL); if(hEvent==NULL) { cout<<"CreateEvent fail"<<endl; } system("pause"); CloseHandle(hEvent); return 0; }