1. 程式人生 > >C++ 執行緒同步之 事件的使用

C++ 執行緒同步之 事件的使用

多執行緒同步有很多方法,現在簡單記錄一下自己的程式對事件的使用。

包含的標頭檔案

#include<Windows.h>

事件的使用步驟:(最簡單的使用步驟)

1、定義一個控制代碼,用於事件的標識。

HANDLE     aEvent;

2、建立事件(可以和第一個合併,注意物件的生存週期和作用範圍):

aEvent  =  CreateEvent(NULL,FALSE,FALSE,NULL);

這樣就建立了一個event,以後這個event就用aEvent標識。

3、等待事件被觸發(這是最核心的地方,與第4步結合使用,用於多執行緒同步)。

WaitForSingleObject(aEvent ,

3000);

意思就是當代碼執行到這的時候,就會在此處阻塞著,直到另外一個執行緒裡觸發這個事件後(第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);