My Study/System

Critical Section(임계 영역) - Mutex

  이번부터는 유저 모드 동기화가 아니라 커널 모드 동기화이다.


  커널 모드 동기화는 유저 모드 동기화 달리 커널 자원과 유저 자원을 사용할 수 있다. 하지만 커널 모드에서 유저 모드로 변경 될 때 딜레이가 발생함으로 유저 모드 동기화보다 느릴 수 있다.


  Mutex는 먼저 뮤텍스를 생성해야한다. 그 다음 임계 영역에서 WaitForSingleObject로 시작해서 ReleaseMutex 로 끝난다.먼저 예시를 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
HANDLE Mutex;
 
unsigned int WINAPI ThreadProc1(LPVOID lpParam)
{
 
    for (DWORD i = 1; i <= 1000; i++)
    {
        WaitForSingleObject(Mutex, INFINITE);
        Sleep(1);
        Count++;
        ReleaseMutex(Mutex);
    }
 
    return 0;
}
 
unsigned int WINAPI ThreadProc2(LPVOID lpParam)
{
    
    for (DWORD i = 1; i <= 1000; i++)
    {
        WaitForSingleObject(Mutex,INFINITE);
        Sleep(1);
        Count++;
        ReleaseMutex(Mutex);
    }
    return 0;
}
 
int _tmain()
{
    Mutex = CreateMutex(NULL, FALSE, NULL);
    //코드 생략
    CloseHandle(Mutex);
}
 
cs


  HANDLE WINAPI CreateMutex(

  _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
  _In_     BOOL                  bInitialOwner,
  _In_opt_ LPCTSTR               lpName
);

출처 : CreateMutex MSDN


  먼저 뮤텍스를 생성한다. 이 API의 첫번째 파라미터는 보안 속성이다. 이 속성에서 핸들을 상속 여부를 결정하는데 이 파라미터를 사용하였다. 두번째 파라미터는 임계 영역에 어떤 것이 먼저 접근하냐를 설정하는 파리미터이다. FALSE 를 사용했을 시에 먼저 선점하는 경우 시작하고, TRUE를 했을 경우 뮤텍스를 생성하는 쓰레드가 먼저 기회를 얻는다. 세번째 파라미터는 뮤텍스에 이름을 줄 수 있다. 그리고 반환형이 핸들임을 생각해보자. 핸들은 커널 오브젝트를 가리킨다. 그럼 뮤텍스는 커널 오브젝트라는 걸 알 수 있다.

  

  커널 오브젝트는 2가지 상태가 있다고 글에서 언급한적이 있다. 뮤텍스는 그것을 이용하여 동기화를 한다.

[커널 오브젝트 글 읽으러 가기]

  먼저 signaled 상태로 변환하는 API는 ReleaseMutex 이다.

BOOL WINAPI ReleaseMutex(
  _In_ HANDLE hMutex
);

출처 : ReleaseMutex MSDN


 non-signaled 상태로 변경해주는 API인 WaitForSingleObject 이다.


DWORD WINAPI WaitForSingleObject(
  _In_ HANDLE hHandle,
  _In_ DWORD  dwMilliseconds
);

출처 : WaitForSingleObject MSDN


  먼저 뮤텍스가 생성이 되어 임계영역 시작 부분에서 WaitForSingleObject 를 만나 뮤텍스는 non-signaled 상태가 된다. 그러면 다른 쓰레드가 접근을 하지 못하다 작업을 끝낸 뒤 ReleaseMutex 로 뮤텍스 상태를 signaled 로 바꿔 다른 쓰레드가 접근할 수있도록 한다.


  뮤텍스를 다 사용했으면 마지막으로 뮤텍스를 반환해야하는데, HANDLE을 반환하는 CloseHandle을 사용하면 된다. 이 사용법은 다들 많이 봤을 테니 패스...


  이번에는 뮤텍스를 생성할 때 세번째 파라미터에 이름을 주었을 때 어떻게 되는지 살펴 보도록 하자.

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<stdio.h>
#include<tchar.h>
#include<Windows.h>
#include<process.h>
 
HANDLE hMutex;
DWORD dwWaitResult;
 
void NamedMutex()
{
    dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
 
    switch (dwWaitResult)
    {
    case WAIT_OBJECT_0:
        _tprintf(_T("Thread Signaled\n"));
        break;
    case WAIT_TIMEOUT:
        _tprintf(_T("Time Out\n"));
        break;
    case WAIT_ABANDONED:
        return;
    }
 
    for (DWORD i = 0; i < 5; i++)
    {
        _tprintf(_T("Thread Runing!!\n"));
        Sleep(1000);
    }
 
    ReleaseMutex(hMutex);
}
 
int _tmain()
{
    hMutex = CreateMutex(NULL, FALSE, _T("Named"));
    _tprintf(_T("CreateMutex!!\n"));
    if (hMutex == NULL)
    {
        _tprintf(_T("CreateMutex Func err : %d\n"), GetLastError());
        return -1;
    }
 
    NamedMutex();
    CloseHandle(hMutex);
    return 0;
}
cs


  먼저 위와 같은 예제를 하나 만든다. 위의 예제는 Named 라는 이름 있는 뮤텍스를 생성하는 간단한 코드이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<stdio.h>
#include<tchar.h>
#include<Windows.h>
#include<process.h>
 
HANDLE hMutex;
DWORD dwWaitResult;
 
void NamedMutex()
{
    dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
 
    switch (dwWaitResult)
    {
    case WAIT_OBJECT_0:
        _tprintf(_T("Thread Signaled\n"));
        break;
    case WAIT_TIMEOUT:
        _tprintf(_T("Time Out\n"));
        break;
    case WAIT_ABANDONED:
        return;
    }
 
    for (DWORD i = 0; i < 5; i++)
    {
        _tprintf(_T("Thread Runing!!\n"));
        Sleep(1000);
    }
 
    ReleaseMutex(hMutex);
}
 
int _tmain()
{
    hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, _T("Named"));
    _tprintf(_T("OpenMutex!!\n"));
    if (hMutex == NULL)
    {
        _tprintf(_T("CreateMutex Func err : %d\n"), GetLastError());
        return -1;
    }
 
    NamedMutex();
    CloseHandle(hMutex);
    return 0;
}
cs




  생성했으니 이제 Named 이름 있는 뮤텍스를 받아보자. 이 두개를 각각 생성해서 실행해보면, 먼저 위의 예제가 실행이 끝난 다음 아래 예제가 실행 되는 것을 확인할 수 있다.
  


HANDLE WINAPI OpenMutex(
  _In_ DWORD   dwDesiredAccess,
  _In_ BOOL    bInheritHandle,
  _In_ LPCTSTR lpName
);
출처 : OpenMutex MSDN


   OpenMutex 는 첫번째 파라미터는 이름 있는 뮤텍스로 접근 권한을 지정하는 것이다. 아래 사이트를 참고해서 원하는 권한만 설정해도 좋고 귀찮으면 역시 MUTEX_ALL_ACCESS  두번째  파리미터는 핸들 상속을 묻는 파라미터이다. 세번째 파라미터는 뮤텍스 이름을 설정해준다. 여기서는 Named 라는 이름 있는 뮤텍스를 열고 있다.


권한 설정 MSDN 글 보기


 

최근 트랙백

알림

이 블로그는 구글에서 제공한 크롬에 최적화 되어있고, 네이버에서 제공한 나눔글꼴이 적용되어 있습니다.