C++ 執行緒同步之 事件的使用
多執行緒同步有很多方法,現在簡單記錄一下自己的程式對事件的使用。
包含的標頭檔案
#include<Windows.h>
事件的使用步驟:(最簡單的使用步驟)
1、定義一個控制代碼,用於事件的標識。
HANDLE aEvent;
2、建立事件(可以和第一個合併,注意物件的生存週期和作用範圍):
aEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
這樣就建立了一個event,以後這個event就用aEvent標識。
3、等待事件被觸發(這是最核心的地方,與第4步結合使用,用於多執行緒同步)。
WaitForSingleObject(aEvent ,
意思就是當代碼執行到這的時候,就會在此處阻塞著,直到另外一個執行緒裡觸發這個事件後(第4步)或者等待超時後,才會繼續往下執行。
(此處的事件若是為NULL,那麼程式會馬上返回一個很大的DWORD (4294967295),程式繼續往下執行,很容易造成程式裡不可思議的錯誤。此處一定要小心)
#include<stdio.h>
#include<Windows.h>
void main()
{
HANDLE hMyEvent;
hMyEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
//while (WaitForSingleObject(hMyEvent, 3000) != WAIT_OBJECT_0)
DWORD result = WaitForSingleObject(NULL, 3000);
while (result != WAIT_OBJECT_0)
{
printf("等待超時!!\n");
}
}
4、觸發事件(與第三步結合使用,進行執行緒同步)。
SETEVENT(aEvent);
當執行緒裡執行完這句程式碼之後,另外一個執行緒中阻塞等待該事件處(第三步)才會繼續往下執行。
5、關閉控制代碼(當這個事件用完之後,要關閉控制代碼釋放資源)。
CloseHandle(aEvent);
例子:(從業務中摘出的程式碼,只作例子,不能執行)
static unsigned int __stdcall GetPortThread(void* param);
uintptr_t g_GetPortTh = NULL;//獲取串列埠號執行緒控制代碼
HANDLE g_GetPortEvent = NULL;//獲取串列埠號事件
LONG g_TheGetPort = -1; // 獲取到的裝置所在串列埠號
g_GetPortEvent = CreateEvent(NULL , TRUE , FALSE , NULL);
main()
{
unsigned int nowBaudRate = 0;
//建立執行緒
g_GetPortTh = _beginthreadex(NULL,0,GetPortThread,NULL,0,NULL);
DWORD waitIndex = WaitForSingleObject(g_GetPortEvent,2000);
if ( WAIT_TIMEOUT == waitIndex )
{
return -1;
}
else
{
return g_TheGetPort;
}
}
unsigned int __stdcall CPatrolCtrlCtrl::GetPortThread(void* param)
{
unsigned int nowBaudRate = 0;
int i = 1;
for (;i<=16;i++)
{
if(SDT_GetCOMBaud(i,&nowBaudRate)==0x90)
{
g_TheGetPort = i;
SetEvent(g_GetPortEvent);//啟用系統介素事件
return 0;
}
}
g_TheGetPort = -1;
return -1;
}
看完最簡單的使用步驟後,就明白了事件到底是幹什麼的。但有時程式設計過程中會遇到很多複雜的情況,這就需要更復雜的使用方法。
主要有幾點:
1、等待事件被觸發函式有:
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);
這個函式的引數:第一個是等待事件的個數,第二個是等待的事件的陣列,第三個是等待事件全部被觸發了才往下執行,還是隻要有一個被觸發了就往下執行,第四個是超時時間。
2、將事件設定為無訊號狀態(被觸發之後重置)
ResetEvent();
在自動重置事件物件中,當WaitSingleObject/WaitForMultipleObjects接收到SetEvent傳送過來的訊號後則返回WAIT_OBJECT_0,此時作業系統(待定)自動重置等待的事件物件(即自動將其設定為無訊號狀態。無論何時通過SetEvent傳送過來的訊號,只要未被接收到均不會被自動重置。但在未被接收之前可以呼叫ResetEvent手動重置等待的事件物件,此時等待的事件物件為無訊號狀態)。在手動重置事件物件中,當WaitSingleObject/WaitForMultipleObjects接收到SetEvent傳送過來的訊號後則返回WAIT_OBJECT_0,此時需要呼叫ResetEvent手動重置等待的事件物件(即手動將其設定為無訊號狀態)。
3、BOOL bManualReset,BOOL bInitialState, LPTSTRlpName);
4、BOOL PulseEvent(HANDLE hEvent);
5、 HANDLE OpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTRlpName);