Windows 平臺下的同步機制 (3)– 事件(Event)

Windows 平臺下的同步機制 (3)– 事件(Event)

事件對象的特點是它可以應用在重疊I/O(overlapped I/0)上,比如說socket編程中有兩種模型,一種是重疊I/0,一種是完成端口都是可以使用事件同步。它也是核心對象,因此可以被waitforsingleobje這些函數等待;事件可以有名字,因此可以被其他進程開啓。

Event即事件是一種用於進行線程/進程間同步的對象,事件有置位和復位兩種狀態,當線程通過waiting functions等待Event對象置位時該線程將進入阻塞狀態,當該Event對象被置位或等待超時後,等待的線程將恢復執行。Event可以用在一個線程要等待其它線程時。
可以使用CreateEvent創建Event對象
HANDLE WINAPI CreateEvent(
    LPSECURITY_ATTRIBUTES lpEventAttributes,
    BOOL bManualReset,
    BOOL bInitialState,
    LPCTSTR lpName
);
lpEventAttributes用於指定Event對象的安全屬性,包括句柄是否可被子進程繼承和對象的安全描述符。可設置NULL取默認安全屬性。
bManualReset表明Event對象是否需要手動復位。如果該參數爲TRUE,則Event對象需要通過ResetEvent函數手動復位。如果該參數爲FALSE,則Event被創建爲自動復位的Event,任何等待的線程被恢復執行後,該Event將被系統自動復位。打個比方,如果有10個線程在等待一個Event,這時將Event置位,如果這是個手動復位Event,那麼這10個線程將被依次喚醒直到通過ResetEvent調用將該Event復位;如果Event爲自動復位Event,那麼10個線程中的第一個被喚醒後Event被自動復位,其它線程將繼續等待。
bInitialState參數表明Event對象被創建後默認是否置位。
lpName參數是Event的名字,可以爲空表明將創建匿名Event。
CreateEvent函數在調用成功後返回Event句柄。如果同名Event已經存在,則返回這個已經存在了的Event的句柄,此時調用GetLastError函數將返回 ERROR_ALREADY_EXISTS。
還可以通過OpenEvent打開一個已經創建的非匿名Event
HANDLE WINAPI OpenEvent(
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    LPCTSTR lpName
);
在創建或打開了Event對象之後,可以使用SetEvent和ResetEvent函數來置位或復位一個Event對象。
BOOL WINAPI SetEvent(
    HANDLE hEvent
);
BOOL WINAPI ResetEvent(
    HANDLE hEvent
);
要等待一個或多個Event對象置位可以使用wait functions。
簡單示例,一個線程不停讀取用戶輸入並放入message列表,另一個線程模擬將message發送出去,如果沒有消息,則發送線程處於阻塞狀態等待,一旦有消息錄入,輸入線程將event置位,發送線程即被激活並逐個發送消息。
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <list>
#include <string>
using namespace std;

#ifdef _UNICODE
typedef wstring tstring;
#define tcout wcout
#define tcin wcin
#else
typedef string tstring;
#define tcout cout
#define tcin cin
#endif /* _UNICODE */

typedef list<tstring> StringList;

HANDLE hMutex = NULL;
HANDLE hEvent = NULL;
HANDLE hSendThread = NULL;
StringList messages;

bool isRunning;

DWORD WINAPI SendThreadProc(LPVOID lpThreadParameter)
{
DWORD dw;
while(isRunning)
{
  dw = WaitForSingleObject(hEvent, INFINITE);
  if(dw != WAIT_OBJECT_0)
  {
   tcout << _T("Wait error.") << endl;
   return -1;
  }
  dw = WaitForSingleObject(hMutex, INFINITE);
  if(WAIT_OBJECT_0 != dw && WAIT_ABANDONED != dw)
  {
   tcout << _T("Wait error.") << endl;
   return -2;
  }

  StringList list(messages);
  messages.clear();

  ReleaseMutex(hMutex);

  for(StringList::iterator i = list.begin(); i != list.end(); i++)
  {
   Sleep(1000); //休眠1秒模擬發送所耗時間

   tcout << _T("/* Send Message:") << *i << _T(" */");
  }

}

return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
hMutex = CreateMutex(NULL, FALSE, NULL);
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
isRunning = true;

hSendThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendThreadProc, NULL, 0, NULL);

while(isRunning)
{
  tstring s;
  tcin >> s;
  if(s == _T("quit"))
  {
   isRunning = true;
   break;
  }

  DWORD dw = WaitForSingleObject(hMutex, INFINITE);
  if(WAIT_OBJECT_0 != dw && WAIT_ABANDONED != dw)
  {
   tcout << _T("Wait error.") << endl;
   return -1;
  }
  messages.push_back(s);
  ReleaseMutex(hMutex);
  SetEvent(hEvent);
}

CloseHandle(hMutex);
CloseHandle(hEvent);
CloseHandle(hSendThread);

return 0;

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章