01 . 실행순서에 있어서의 동기화
쓰레드의 실행순서를 동기화한다 = 메모리에 접근하는 쓰레드의 실행순서를 동기화한다.
따라서 "실행순서 동기화"라는 것은 "메모리 접근 동기화"를 포함하는 개념이다.
-생산자/소비자 모델
생산자는 문자열을 생성한다(입력받는다). 반면에 소비자는 생산된 문자열을 소비한다(출력한다).
-이벤트 기반 동기화
세마포어나 뮤텍스와 같이 이 기법에서도 동기화를 위한 오브젝트가 사용된다. 여기서 사용되는 오브젝트를 가리켜 "이벤트 오브젝트" 보편적으로 이벤트라고 부른다.
다음은 이벤트 오브젝트를 생성하는 데 사용되는 함수이다.
HANDLE CreateEvent (
LPSECURITY_ATTRIBUTES lpEventAttributes // 보안 속성을 지정할 때 사용한다. 핸들을 자식 프로세스에게 상속한고자 할경우 NULL이 아닌 다른 값을 전달한다.
BOOL bManualReset // 이 함수의 가장 중요한 전달인자로서 TRUE가 전달될 경우 수동 리셋 모드 이벤트 오브젝트가 FALSE가 전달될 경우 자동 리셋 모드 이벤트 오즈젝트가 생성된다는 것만 기억하자.
BOOL bInitialState //이벤트 오브젝트의 초기 상태를 결정짓는다. TRUE가 전달될 경우 Signaled 상태의 이벤트 오브젝트가 생성되고, FALSE가 전달될 경우 Non-Signaled 상태의 이벤트가 생성된다.
LPCTSTR lpName // 이벤트 오브젝트에 이름을 줄 경우에 사용하는 전달인자이다. NULL을 전달하면 이름없는 이벤트 오브젝트가 생성된다.
);
이벤트 오브젝트를 소멸시킬 때에는 여느 커널 오브젝트와 마찬가지로 ClostHandle 함수를 사용하면 된다.
쓰레드나 프로세스의 커널 오브젝 경우, 초기에는 Non_Signaled 상태로 생성된다, 그러나 쓰레드나 프로세스가 종료될 경우 해당 커널 오브젝트는 Signaled 상태로 자동변경된다 그러나 이벤트 오브젝트는 자동으로 Signaled 상태가 되지않는다.
이벤트 오브젝트가 Signaled 상태가 되어 블로킹 상태에 있던 쓰레드가 빠져나온다면, 빠져 나온 이후 이벤트 오브젝트는 수동 리셋 모드의 경우 Signaled 상태 그대로, 자동 리셋 모드의 경우 Non-Signaled 상태로 자동 변경
내용정리
이벤트 오브젝트의 상태를 변경시키는 두 함수
BOOL ResetEvent (
HANDLE hEvent // 이벤트 오브젝트의 핸들을 인자로 전달한다. 전달된 핸들의 오브젝트는 Non-Signaled 상태가된다.
);
BOOL SetEvent (
HANDLE hEvent // 이벤트 오브젝트의 핸들을 인자로 전달한다. 전달된 핸들의 오브젝트는 Siganled 상태가 된다.
);
수동 리셋 모드 이벤트는 둘 이상으 쓰레드를 동시에 꺠워서 실행해야 할 때 아주 좋은 도구가 될 수 있다.
02 . 이벤트 더하기 뮤텍스
이벤트 오브젝트로는 생산자/소비자 모델을 구현하였고, 이 과정에서 소비자가 둘 이상인 관계로 이 둘 사이에서의 동기화를 위해서 뮤텍스를 적용한다.
03 . 타이머 기반 동기화
타이머 동기화 오브젝트는 " 정해진 시간이 지나면 자동으로 Signaled상태가 되는 특성을 지닌다.
타이머를 기반으로 쓰레드를 동기화한다는 것은 임계 영역 문제 해결을 위한 동기화와는 그 관점이 다르다
타이머 기반 동기화는 다음과 같이 두 가지 형태로 구분 지을 수 있다.
수동 리셋 타이머 : 가장 일반적인 타이머로서, 알람 시계를 생각하면 된다, 새벽 6시에 알람을 맞춰놓으면 새벽 6시에 시계가 울린다. 이러한 특성의 타이머다.
주기적타이머 : 수동 리셋 타이머에 주기적인 특성이 가해진 형태로 이해하면된다 6시이후 주기적으로 30분마다 알람이 울린다.
타이머라는 단어 자체가 여러분에게 친근하게 느껴질 것이다. 그리고 이름에서부터 전달되는 느낌만으로도 이 커널 오브젝트의 특성을 짐작할 수 있다. 타이머 오브젝트는 정해진 시간이 지나야 Signaled 상태가 되는 커널 오브젝트이다.
타이머 오브젝트를 생성하는 함수
HANDLE CreateWaitableTimer (
LPSECURITY_ATTRIBUTES lpTimerAttributes // 보안 속성을 지정하는 데 사용된다. 핸들을 자식 프로세스에게 상속하고자 할 경우 NULL이 아닌 다른 값을 전달한다.
BOOL bManualReset // 타이머 오브젝트를 수동 리셋 모드로 생설할 것인지, 자동 리셋 모드로 생성할 것인지를 결정
lpTimerName // 타이머 오브젝트에 이름을 붙여줄 경우에 사용되는 전달인자이다. NULL을 전달하면 이름없는 타이머 오브젝트가 생성된다.
);
CreateEvent 함수와의 차이점 초기값을 Signaled로 할것인지 묻지않음 Why? - 바로 알람이 울리면 의미가없다 타이머 오브젝트는 무조건 Non-Signaled 상태로 생성됨
알람 시간을 설정하는 함수
BOOL SetWaitableTimer (
HANDLE hTimer // 알람을 설정할 타이머 오브젝트의 핸들을 인자로 전달한다. 정해진 시간이 되면 이 인자로 전달된 핸들의 커널 오브젝트느 Signaled 상태가 된다.
const LARGE_INTEGER* pDueTime // 커널 오브젝트가 Signaled 상태가 되는 시간)을 지정하기 위한 매개변수이다. + 값이 전달되면 절대시간을 의미하게 되고, - 값이 전달되면 상대시간을 의미하게 된다. 1000만 분의 1초 다위로 시간을 설정한다.
LONG lPeriod // 타이머가 주기적으로 알람을 울리게 할 때 사용하는 전달인자이다. 주기가 되는 시간 간격을 1/1000초 단위로 전달하면 된다. 0을 전달할 경우 주기적인 알람을 사용하지 않겠다는 의미가 된다.
PTIMERAPCROUTINE pfnCOmpletionRoutine
LPVOID lpArgTOCompletionRoutine // 완료 루틴 타이머를 생성하는 용도의 함수
BOOL fResume // 전원관리와 관련 있는 매개변수, 기본적으로 FALSE 전달은 원칙으로 한다.
);
#define _WIN32_WINNT 0x0400 : 이 매크로는 다음과 같이 선언한다. "아레의 프로그램은 Windows NT 이상에서 실행하겠습니다(그러니 SetWaitableTimer 함수의 호출을 허용해 주십시오)
BOOL CancelWaitableTimer (
HANDLE hTimer // 알람을 해제할 타이머 오브젝트의 핸들을 전달한다. 전달된 핸들의 타이머 오브젝트는 알람이 해제된다.
);
이 함수는 가동 중에 있는 타이머를 중지시키는 기능의 함수이지, 타이머를 소멸시키거나 할당된 자원을 반환하는 종류의 함수가 아니라는 점이다. 할당된 자원을 반환하고 소멸을 시키고자 할 경우에는 여느 커널 오브젝트와 마찬가지로 CloseHandle 함수를 호출하면 된다.
이것만은 알고 갑시다.
쓰레드의 실행순서가 중요한 이슈인 경우에는 실행순서 동기화를 고려해야 한다. 이를 위해서 Windows에서는 이벤트 오브젝트 기반의 동기화 기법을 제공한다.
타이머 역시 동기화 오브젝트이다. 다른 동기화 오브젝트와 달리 일정 시간이 지나면 자동으로 Signaled 상태가 되는 특성을 지니고 있어서 타이머라 한다
이 단원에서 이벤트와 뮤텍스를 혼용한 동기화 사례를 보여주고 있는데, 실제로 프로그램을 개발하다 보면 이보다 훨씬 복자반 구성의 동기화가 필요한 경우도 많다, 쓰레드를 사용한다는 것은 여러 가지로 편리하고,쓰레드 기반으로 프로그램을 구상할 경우 초반 설계도 훨씬 수월하다. 그러나 실제 구현에 들어가면 예상치 못한 일을 경험하게 된다. 이러한 문제를 미연에 막기 위해서는 동기화 기법을 정확히 알고 아는 만큼만 적용하는 지혜가 필요하다.