실행 순서의 동기화 -----------------------------------------------------------------------------------------


이전까지 하나의 공유객체에 대해서 접근하는 방법에 대해서 알아보았다.
다음은 쓰레드의 실행순서를 동기화하는 차례이다.
쓰레드의 연산이나 메모리에 접근하는 실행순서를 동기화 한다.

A, B, C쓰레드가 있다고 할때 A의 연산결과를 B가 받아서 연산하고 B의 연산결과를 C가 받아서 연산해야 한다면 A B C는 순차적으로 실행되어야 한다. 이러한 상황을 위해서 실행 순서의 동기화가 필요하다. 순차적으로 실행되지 않는다면 분명 원하지 않는 값이 나오거나 이상한 값이 나올것이 뻔하다.


이벤트 기반의 동기화 -----------------------------------------------------------------------------------------

이벤트 기반의 동기화 모델에 있어서 프로그램의 추상화 개념과 비슷하게 비교해 본다면. A와 B쓰레드가 존재하고 A 쓰레드는 생산자, B 쓰레드는 소비자라는 개념을 든다.

"A생산자가 특정 물건을 만들기 전까지는 B소비자는 물건을 소비할 수 없다."

다른 비유를 들어보다면 이런 느낌을 가질 수 있습니다.

"A생산자가 가게문을 열기전까지 B소비자는 가게안에 들어와 물건을 구매할 수 없다."

커널기반이므로 당연히 윈도우에서 이에대한 지원 함수가 존재합니다.

-> 사용 방식

HANDLE CreateEvent(

  LPSECURITY_ATTRIVUTES lpEventAttributes, 

  BOOL bManualReset,

  BOOL bInitialState,

  LPCTSTR lpName

);

  LPSECURITY_ATTRIVUTES lpEventAttributes, -> 보안속성 지정

  BOOL bManualReset,-> 가장 중요한 전달인자 수동리셋모드로 이벤트 오브젝트를 생성하느냐, 자동 리셋 모드로 이벤트 오브젝트를 생성하느냐를 결정짓는다. TRUE로하면 수동리셋모드 FALSE가 전달될 경우 자동리셋 모드로 이벤트의 커널 오브젝트가 생성된다.

  BOOL bInitialState -> 이벤트 오브젝트의 초기상태를 설정한다. TRUE가 전달될 경우 Signaled 상태의 이벤트 오브젝트가 생성되고, FALSE가 전달될 경우 Non-Signaled 상태의 이벤트가 생성된다.

  lpName 이벤트 오브젝트에 이름을 줄 경우에 사용하는 전달인자이다. NULL을 전달하면 이름 없는 이벤트 오브젝트가 생성된다.


-> 종료 방식

  이벤트 오브젝트를 소멸시킬 때에는 다른 커널 오브젝트와 마찬가지로 CloseHandle 함수를 사용하면 된다.


 여기서 잠깐! WaitForSingleObject -----------------------------------------------------------------------------

 커널 오브젝트를 읽을때 그냥 넘어갔던 함수가 있었는데 여기서 다시 설명해야할 듯 하다. WaitForSingleObject함수가 존재하는데 이 함수는 핸들을 인자로 적용해서 커널 오브젝트의 상태를 확인하는데 사용되는 함수이다. 

 DWORD WaitForSingleObject {

HANDLE hHandle,         -> 커널 오브젝트의 핸들

DWORD dwMilliseconds -> 커널오브젝트가 종료될때까지 기다려주는 값 밀리세컨트단위를 사용한다.

}

이 함수가 반환하는 값은 다음과 같다.

 Priority 

 meaning 

 WAIT_OBJECT_0

 커널 오브젝트가 Signaled 상태가 되면 반환하는 값

 WAIT_TIMEOUT

 커널 오브젝트가 Signaled 상태가 되지 않고, dwMilliseconds 인자를 통해서 설정된 시간이 다 된 경우에 반환하는 값

 WAIT_ABANDONED

 소유 관계와 관련하여 함수가 정상적이지 못한 오류 발생에 의해서 반환되는 값


이벤트 기반의 동기화의 개념 -----------------------------------------------------------------------------------

  앞선 설명으로 커널 오브젝트는 이벤트 커널 오브젝트는 다른 쓰레드나 프로세스의 커널 오브젝트와 달리 자동으로 Signaled상태가 되지 않는다. 순서로 설명하자면.

 1. 이벤트 오브젝트 핸들을 전역으로 선언

 2. 메인 쓰레드가 이벤트 오브젝트를 생성한다.

 3. 쓰레드 A를 생성한다.

 4. 쓰레드 A에서 hEvent WaitForSingleObject를 호출한다. 이 의미는 이벤트가 signaled가 되기를 기다리는 것을 의미한다.

 5. 메인쓰레드에서는 쓰레드A의 핸들로 WaitForSingleObject를 호출한다.

 이 경우 4번의 과정에서 WaitForSingleObject의 호출로 signaled상태가 된 이벤트 오브젝트는 어떠한 상태가 될 것인가?

 signaled인가? Non-signaled인가?  

 정답은 BOOL bManualReset인자가 TRUE(수동 리셋 모드)라면  signaled.

 bManualReset인자가 FALSE(자동 리셋 모드)라면  Non-signaled이다.


정리하자면.

1. 이벤트 커널 오브젝트는 프로그래머의 요청에 의해서 Signaled 상태가 된다.

2. Non-Signaled 상태의 이벤트 오브젝트 때문에 WaitForSingleObject 함수 호출이 블로킹 되었다면, Signaled 상태가 되는 순간 블로킹된 함수를 빠져 나오게 된다. 그리고 이때 자동 리셋 모드 이벤트 오브젝트라면 Non-Signaled 상태로의 변경은 자동으로 이루어 진다.

3. 이중 수동 리셋모드는 둘 이상의 쓰레드를 동시에 깨워서 실행해야 할 때 아주 좋은 도구가 될 수 있다.

Posted by JJOREG