뮤텍스의 생성 및 실행
- CreateMutex : 성공 시 Mutex 핸들, 실패 시 NULL 반환
-> 커널 오브젝트 생성을 동반하기 때문에 핸들도 반환되고 핸들 테이블의 상속을 결정하는 보안 설정을 함
-> 소유자를 지정하면 열쇠를 만든사람이 소유하는지 열쇠를 만든 사람도 소유의 권한을 가지지 않고 누구나 소유할 수 있는 지를 결정
HANDLE CreateMutexA(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 보안 설정
BOOL bInitialOwner, // 열쇠의 소유
LPCSTR lpName // 뮤텍스 이름
);
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
); // 지정한 오브젝트가 Signaled 상태가 되기를 기다리는 함수
BOOL ReleaseMutex(
HANDLE hMutex
);
- WaitForSingleObject(), ReleasMutex()를 통해서 뮤텍스(열쇠)를 획득하고 반납
- 뮤텍스를 커널 오브젝트라고 생각하면 WaitForSingleObject()가 빠져나오기 위해선 뮤텍스가 Signaled 상태가 되야 함
-> ReleaseMutex()는 뮤텍스를 Signaled 상태가 되게 하는 함수
-> WaitForSingleObject()는 뮤텍스를 Non-Signaled 상태로 바꾸게 되는 함수
- 쓰레드가 임계 영역으로 들어가기 전 뮤텍스를 얻기 위해 뮤텍스 핸들을 인자로 전달하면서 WaitForSingleObject() 함수를 호출하고 뮤텍스가 획득 가능 상태라면 Signaled 상태에 있고 뮤텍스를 획득하면서 임계 영역에 진입
- WaitForSingleObject 함수는 매개변수로 호출한 오브젝트가 Signaled 상태가 되기를 기다리기 때문에 다른 쓰레드는 임계 영역으로의 진입이 불가능
- 임계 영역에 진입한 쓰레드가 빠져나오면서 ReleaseMutex 함수를 호출하면 뮤텍스는 Signaled 상태가 되어 다른 쓰레드가 획득할 수 있게 되어 다른 쓰레드의 진입을 허용함
int main(int argc, char *argv[])
{
HANDLE tHandles[NUM_THREAD];
int i;
hMutex=CreateMutex(NULL, FALSE, NULL);
for(i=0; i<NUM_THREAD; i++)
{
if(i%2)
tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
else
tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
}
WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
CloseHandle(hMutex);
printf("result: %lld \n", num);
return 0;
}
unsigned WINAPI threadInc(void * arg)
{
int i;
WaitForSingleObject(hMutex, INFINITE);
for(i=0; i<50000000; i++)
num+=1;
ReleaseMutex(hMutex);
return 0;
}
unsigned WINAPI threadDes(void * arg)
{
int i;
WaitForSingleObject(hMutex, INFINITE);
for(i=0; i<50000000; i++)
num-=1;
ReleaseMutex(hMutex);
return 0;
}
세마포어의 생성 및 실행
HANDLE CreateSemaphoreA(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
// 세마포어가 가지는 열쇠의 개수(값) = 임계 영역에 동시 접근할 수 있는 쓰레드 수
LONG lMaximumCount, // 세마포어가 가질 수 있는 최대 열쇠의 수 (InitialCount 이상)
LPCSTR lpName
);
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lpPreviousCount
);
- WaitForSingleObject, ReleaseSemaphore 함수가 호출되면 세마포어 카운트가 감소 / 증가됨
- 세마포어 카운트 값이 0이 되면 Non-signaled 상태가 됨
- Signaled 상태로 계속 있기 때문에 WaitForSingleObject를 호출해도 임계 영역에 다른 쓰레드도 진입 가능
static HANDLE semOne;
static HANDLE semTwo;
static int num;
int main(int argc, char *argv[])
{
HANDLE hThread1, hThread2;
semOne=CreateSemaphore(NULL, 0, 1, NULL);
semTwo=CreateSemaphore(NULL, 1, 1, NULL);
hThread1=(HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);
hThread2=(HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
CloseHandle(semOne);
CloseHandle(semTwo);
return 0;
}
unsigned Read(void * arg)
{
int i;
for(i=0; i<5; i++)
{
fputs("Input num: ", stdout);
WaitForSingleObject(semTwo, INFINITE);
scanf("%d", &num);
ReleaseSemaphore(semOne, 1, NULL);
}
return 0;
}
unsigned Accu(void * arg)
{
int sum=0, i;
for(i=0; i<5; i++)
{
WaitForSingleObject(semOne, INFINITE);
sum+=num;
ReleaseSemaphore(semTwo, 1, NULL);
}
printf("Result: %d \n", sum);
return 0;
} // 세마포어로 실행 순서 조절
이벤트의 생성 및 실행
- createEvent : 성공 시 Event 핸들, 실패 시 NULL 반환
-> bManualReset : True 전달 시 manual-reset 모드, False 전달 시 auto-reset 모드
-> bInitialState : True 전달 시 signaled 상태, False 전달 시 non-signaled 상태의 오브젝트 생성
HANDLE CreateEvent (LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset,
WINBOOL bInitialState, LPCWSTR lpName);
- 이벤트 상태의 변경 : manual-reset 모드로 생성했으면 상태를 수동으로 변경
BOOL SetEvent (HANDLE hEvent); // non-signaled로 변경
BOOL ResetEvent (HANDLE hEvent); // signaled로 변경
'Programming > Network' 카테고리의 다른 글
열혈 TCP/IP 21-2. 비동기 Notification IO 모델의 이해와 구현 (0) | 2021.04.13 |
---|---|
열혈 TCP/IP 21-1. 비동기 Notification IO 모델의 이해 (0) | 2021.04.13 |
열혈 TCP/IP 20-1. 동기화 기법의 분류와 CRITICAL_SECTION 동기화 (0) | 2021.04.11 |
열혈 TCP/IP 19-3. 커널 오브젝트의 두 가지 상태 (0) | 2021.04.11 |
열혈 TCP/IP 19-2. 윈도우 기반의 쓰레드 생성 (0) | 2021.04.11 |