이벤트란 어떤 사건이 일어났음을 알리는 동기화 객체이다?
- 크리티컬섹션, 뮤텍스, 세마포어는 주로 공유자원을 보호하기 위해 사용되는 데 비해 이벤트는 그보다는 스레드간의 작업 순서나 시기를 조정하고 신호를 보내기 위해 사용한다.
이벤트는 윈도우의 메시지와 유사하다?
- 사용자가 키보드 누를 때 WM_KETDOWN 메시지를 윈도우 프로시저에게 보내 처리하게 하는 것처럼 정렬이나 다운로드가 끝났을 때 이벤트를 보내 관련된 다른 작업을 하도록 지시할 수 있다.
자동 리셋 이벤트 |
대기 상태가 종료되면 자동으로 비신호상태가 된다. |
수동 리셋 이벤트 |
스레드가 비신호상태로 만들 때까지 신호상태를 유지한다. |
이벤트 함수정리
이벤트생성함수
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL blnitialState, LPCTSTR lpname);
lpEventAttributes |
보안속성 |
bManualReset |
TRUE이면 수동 리셋 이벤트 FALSE이면 자동 리셋 이벤트 |
blnitialState |
TRUE이면 이벤트를 생성함과 동시에 신호상태로 만든다. |
lpname |
이름 |
세마포어와 마찬가지로 첫번째, 네번째인자는 프로세스동기화와 관련있다.
n 이벤트가 뮤텍스나 크리티컬섹션과 또 다른 점은 대기 함수를 사용하지 않고도 임의적으로 신호상태나 비신호상태를 설정할 수 있다는 점이다. 이때 쓰는 함수가 아래와 같다.
신호상태변경함수
BOOL SetEvent(HANDLE hEvent)
BOOL ResetEvent(HANDLE hEvent)
SetEvent |
신호상태로 만든다. |
ResetEvent |
비신호상태로 만든다. |
이런 상태변화가 대기중인 스레드에게는 일종의 신호로 전달된다.
자동 리셋 이벤트
• 대기 상태를 풀 때 자동으로 이벤트를 비신호상태로 만든다는 뜻이다.
• 여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하지않다.
수동 리셋 이벤트
• 대기 상태를 풀 때 신호 상태를 그대로 유지하고 ReSerEvent 함수로 일부러 비신호상태로 만들 때만 상태가 변경된다.
• 여러 개의 스레드가 하나의 이벤트를 기다리고있을때 적합하다.
함수 사용 예제
HANDLE hEvent;
DWORD WINAPI ThreadSend(LPVOID temp)
{
WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기
HDC hdc=GetDC(hWndMain);
TextOut(hdc,210,100,"전송완료",8);
ReleaseDC(hWndMain, hdc);
return 0;
}
DWORD WINAPI ThreadSave(LPVOID temp)
{
WaitForSingleObject(hEvent,INFINITE); //신호상태가 될때까지 무한정대기
HDC hdc=GetDC(hWndMain);
TextOut(hdc,110,100,"저장완료",8);
ReleaseDC(hWndMain, hdc);
return 0;
}
DWORD WINAPI ThreadCalc(LPVOID temp)
{
HDC hdc=GetDC(hWndMain);
for (int i=0;i<10;i++) {
TextOut(hdc,10,50,"계산중",6);
GdiFlush();
Sleep(300);
TextOut(hdc,10,50,"기다려",6);
GdiFlush();
Sleep(300);
}
TextOut(hdc,10,50,"계산완료",8);
ReleaseDC(hWndMain, hdc);
SetEvent(hEvent); //신호상태로 바꿔줌
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
DWORD ThreadID;
TCHAR *Mes="마우스 왼쪽 버튼을 누르면 계산을 시작합니다";
switch (iMessage) {
case WM_CREATE:
hWndMain=hWnd;
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL); //수동이벤트
//hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); // 자동 이벤트
return 0;
case WM_LBUTTONDOWN:
InvalidateRect(hWnd,NULL,TRUE);
ResetEvent(hEvent);
CloseHandle(CreateThread(NULL, 0, ThreadCalc, NULL, 0, &ThreadID));
CloseHandle(CreateThread(NULL, 0, ThreadSave, NULL, 0, &ThreadID));
CloseHandle(CreateThread(NULL, 0, ThreadSend, NULL, 0, &ThreadID));
return 0;
case WM_PAINT:
hdc=BeginPaint(hWnd, &ps);
TextOut(hdc,10,10,Mes,lstrlen(Mes));
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
CloseHandle(hEvent);
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
WM_CREATE에서 이벤트 객체를 생성하는데 이 때 두 번째 인수로 TRUE를 지정하여 수동 리셋 이벤트가 되도록하였다.
가장 위 에 있는 계산스레드가 실행이되는데 계산이 완료되면 SetEvent함수를 호출하여 신호상태로 만든다.
신호상태로 바뀌어지면 대기하고있던 스레드들이 모두 실행 할 수 있다.
단, 자동리셋은 같은 상황에서 계산스레드가 끝나고 다른 스레드가 실행되는데 그 스레드가 대기함수를 거치면서 신호를 비신호상태로 바꿔놓음으로서 다른 스레드들은 또 대기를 해야한다.
출처 - 윈도우즈 API 정복 , 한빛미디어