// Kernel object Mutex Thread 동기화 예제
// 1.signaled == 소유가 가능한 상태:
// WaitForSingleObjet 함수를 호출하여 전달된 mutex Handle인자를
// non-signaled 상태로 변경하여 이미 소유되어진 상태로 만든다. (소유 잠금 함수)
// non-signaled == 이미 소유되어진 상태:
// ReleaseMutex 함수를 호출하여 전달된 mutex Handle인자를
// singnaled 상태로 변경하여 소유가능 상태로 만든다. (소유 해제 함수)
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
DWORD WINAPI ThreadIncrement(void *arg);
void ErrorHandling(char *message);
char thread1[] = "A Thread";
char thread2[] = "B Thread";
// 임계영역에 해당되는 전역변수 선언
// 다중 thread함수에 의해 값이 변경되는 변수
int number = 0;
// 핸들 자료형으로 mutex핸들로 사용할 변수 선언
HANDLE hMutex;
int main(int argc, char *argv[])
{
HANDLE hThread[2]; // 핸들 자료형으로 thread핸들로 사용할 변수 선언
DWORD dwThreadID[2]; // 생성되는 thread의 ID로 사용할 변수 선언
// mutex를 생성
// (보안관련 설정: NULL, 소유여부 설정: FALSE(==signaled) , Mutex이름: NULL)
// 소유가 가능한 상태로 mutex 를 생성
hMutex = CreateMutex(NULL, FALSE, NULL);
// mutex 생성 실패시 처리
if(hMutex==NULL)
ErrorHandling("CreateMutex() Error");
// thread에 안전한 함수 호출 방식으로 thread함수 호출함과 인자를 넘겨 주면서 thread ID생성
hThread[0] = (HANDLE) _beginthreadex(NULL, 0, ThreadIncrement, (void*)thread1, 0, &dwThreadID[0]);
hThread[1] = (HANDLE) _beginthreadex(NULL, 0, ThreadIncrement, (void*)thread2, 0, &dwThreadID[1]);
// thread 생성 실패시 처리
if(hThread[0] == 0 || hThread[1] == 0)
ErrorHandling("_beginthreadex() Error");
// thread함수 처리 종료 까지 대기한다.
if(WaitForMultipleObjects(2, hThread, TRUE, INFINITE) == WAIT_FAILED)
ErrorHandling("WaitForMultipleObjects() Error");
// thread함수에 의해 변경된 임계영역에 해당하는 number 값을 출력
printf("main() function end, last number : %d \n", number);
// 생성되었던 mutex핸들을 소멸 시킨다.
// CloseHandle함수는 어떠한 handle이라도 소멸 시킬수 있다.
// 여기서는 mutex 핸들을 소멸 시키는 것을 보여주고 있다
CloseHandle(hMutex);
return 0;
}
DWORD WINAPI ThreadIncrement( void *arg )
{
int i;
for(i=0; i<5; i++){
// mutex를 non-signaled 상태로 변경(소유를 한다음 소유 불가능 상태로 잠금)
WaitForSingleObject(hMutex, INFINITE);
Sleep(100); // 실행결과를 눈으로 확인 하기 위해 사용 ^^
number++;
printf("Run : %s, number : %d \n", (char*)arg, number);
// mutex를 signaled 상태로 변경(소유를 포기한다음 소유가능 상태로 해제함)
// 참고로 참조하는 부분도 mutex로 묶어준 이유는 참조하는 순간 다른 thread함수에 의해
// 값이 변경되는 것을 막기 위함이다.
ReleaseMutex(hMutex);
}
return 0;
}
void ErrorHandling( char *message )
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}