이 글의 목적은 CEvent의 사용 목적 및 방법과 WaitForSingleObject(wait function)와의 사용관계에 대한 간단한 설명입니다.



CEvent는 보통 이벤트 객체라고 불리며, 동기화 객체로 사용됩니다. 이 이벤트 객체는 딱 2가지 상태(signaled, non-signaled 또는 unsignaled)로 동기화를 지원합니다.

예를 들어 TRUE, FALSE 와 같은 개념입니다. 그럼 이 두 상태를 바탕으로 우리가 할 수 있는 일은 대부분 동기화 , 즉 둘 이상의 관계에서 서로간의 상태에 따라 작업을

구분지어 실행 순서에 제어를 두기 위함입니다. 예를 들어 두 스레드간에 서로 같은 데이터를 접근하여 사용하는 경우이겠죠.



CEvent의 생성자를 살펴보면, 다음과 같습니다.

CEvent::CEvent

(

  BOOL bInitiallyOwn = FALSE,

  BOOL bManualReset = FALSE,

  LPCTSTR lpszName = NULL,

  LPSECURITY_ATTRIBUTES lpsaAttribute = NULL

);



여기서 주의 깊게 보아야 할 부분이 bInitiallyOwn, bManualReset 입니다.

bInitiallyOwn 을 FALSE로 지정할 경우 생성되는 event 객체는 non-signaled된 상태입니다. 반대일 경우는 signaled로 생성이 됩니다.



그럼 bManualReset의 상황에 따라 WaitForSingleObject의 수행이 어떻게 다른가 살펴보겠습니다. (단, bInitiallyOwn 는 FALSE)



1. bManualReset = TRUE 일 경우 ( 수동 event 객체)



WaitforSingleObject를 통해서 스레드나 프로세스가 대기하게 됩니다. 물론 같은 event 객체에 대한 WaitForSingleObject가 수행된 곳은 모두 대기 상태입니다. 더 이상 실행이

진행이 안되는 것이죠. 이 상황에서 SetEvent()를 호출하면 내부적으로 event 객체가 signaled로 변경됩니다. 각 대기 스레드나 프로세스들은 (현재 대기하는 모든 스레드나 프로세스) 가 대기상태 에서 진행상태로 바뀌게 됩니다  SetEvent()로 인하여 event 객체는 계속 signaled된 상태를 지속하게 됩니다. 이 event 객체의 상태를 non-signaled로 바꾸려면, ResetEvent()를 호출시켜줍니다. 이 경우는 같은 event 객체를 사용하고 , waitForSIngleObject를 통해서 대기하는 모든 스레드나 프로세스가 같이 대기 상태에서

진행상태로 바꾸게 됩니다.  그리고, ResetEvent()를 통해 다시 대기 상태로 변경시킬 수 있습니다. 이 경우 PulseEvent()함수는 Event의 상태를 signaled로 변경하고 ,

모든 대기 스레드나 프로세스를 대기상태에서 벗어나게 합니다. 그리고 나서 자동으로 non-signaled로 변경시켜줍니다.



2. bManualReset = FALSE 일 경우 ( 자동 event 객체)



WaitforSingleObject를 통해서 스레드나 프로세스가 대기하게 됩니다. 물론 같은 event 객체에 대한 WaitForSingleObject가 수행된 곳은 모두 대기 상태입니다.

이 상황에서 SetEvent()를 호출하면 내부적으로 event 객체가 signaled로 변경됩니다. 현재 대기하는 모든 스레드나 프로세스 중에서 하나의 스레드나 프로세스만이 대기상태에서 진행상태로 바뀌게 됩니다. 그리고 자동으로 non-signaled 상태가 되어 다른 스레드나 프로세스가 진행상태로 되는 것을 방지해줍니다. 물론 꼭 하나의 스레드나 프로세스가 대기상태에서 진행 상태로 변경되어야만 non-signaled 상태가 됩니다. ResetEvent()는 자동 event 객체일때는 사용할 수 없습니다. 이 경우 PulseEvent()함수는 Event의 상태를 signaled로 변경하고 , 현재 대기하는 모든 스레드나 프로세스 중에서 하나의 스레드나 프로세스만이 대기상태에서  벗어나게 합니다. 그리고 나서 자동으로 non-signaled로 변경시켜줍니다.



보통 다중 스레드에서 하나의 데이터에 접근할 때 쓰는 방법은 2번이 되겠습니다. 1번의 경우는 각 스레드들이 작업을 진행하다가 어떤 이벤트에 의해서 모두 정지되거나 진행되어야 할 때 유용하게 사용할 수 있습니다.



예제) bInitiallyOwn = FALSE, bManualReset = FALSE일 경우

Thread1()

{

  while(condition)

  {  

      0.  WaitForSingleObject( event, INFINITE);

      2. // 작업...                                              

      3. SetEvent();

  }

}



Thread2()

{

  while(condition)

  {

      0. WaitForSingleObject(event, INFINITE);

      4. //작업

      5. SetEvent();

  }

}



otherFunction()

{

  1.  SetEvent();

}

위의 예제에서는 //작업이라는 구역에는 동시에 두 스레드가 접근할 수 없습니다. 이해가 되실꺼에요. 3. 5번으로 인하여 두 스레드는 계속 루프를 돌게 됩니다. while이 있지만, 서로가 서로에게 계속 이벤트를 발생시켜줌으로서 운영체제의 스레드 스케쥴링에 의해서 계속 루프를 돌면서 수행되는 이야기입니다. 만약 스레드 안에 3. 5번을 없애면 1번 처럼

이벤트를 날려줌으로 해서 스레드의 작업을 제어할 수 있습니다.

'프로그래밍 > MFC' 카테고리의 다른 글

MFC 디렉토리 생성  (0) 2013.08.14
쓰레드 생성 (펌글)  (0) 2013.08.14
쓰레드 생성.  (0) 2013.08.14
유니코드  (0) 2013.08.14
CEvent 클래스  (0) 2013.08.14
JPG to BMP , BMP to JPG 로 변환 코드  (0) 2013.08.14

+ Recent posts