728x90
반응형

[Windows 제공 동기화 기법]

1.  크리티컬 섹션(Critical Section)기반의 동기화: 유저 모드 동기화, 메모리 접근 동기화

 -  크리티컬 섹션 오브젝트를 선언한 다음 InitializeCriticalSection()을 통해 초기화 과정을 거쳐야한다. 이 과정을 통해서 크리티컬 섹션 오브젝트는 사용 가능한 상태가 된다. EnterCriticalSection()를 이용하여 임계 영역 진입을 위해 크리티컬 섹션 오브젝트 획득. LeaveCriticalSection()는 크리티컬 섹션 오브젝트 반환. 임계 영역이 결정되면 진입 이전에 “EnterCriticalSection() 호출”, 빠져 나온 후에 “LeaveCriticalSection() 호출하여 이 영역은 한 순간에 하나의 쓰레드만 실행할 수 있도록 구성. 마지막으로 DeleteCriticalSection()을 이용하여 초기화 함수가 호출되는 과정에서 할당된 리소스들을 반환한다.

 

2.  인터락 함수(Interlocked Family Of Function)기반의 동기화: 유저 모드 동기화, 메모리 접근 동기화

-  함수 내부적으로 한 순간에 하나의 쓰레드에 의해서만 실행되도록 동기화. InterlockedIncrement()InterlockedDecrement()는 한 순간에 하나의 쓰레드만 접근하는 것(원자적 접근)을 보장해 주는 함수. 모든 쓰레드가 이 함수들을 통해서 값을 하나 증가시키거나 감소시킬 경우, 동시에 둘 이상의 쓰레드 접근에 의한 문제는 발생하지 않음. (크리티컬 섹션 동기화 기법도 내부적으로는 인터락 함수를 기반으로 구현되어 있음). 속도가 상당히 빠름.

*volatile로 선언: 전달되는 포인터를 이용해서 함수 내부적으로 최적화를 수행하지 않으며, 해당 포인터가 가리키는 메모리 영역을 캐쉬하지 않겠다는 것을 의미.

 

3.  뮤텍스(Mutex)기반의 동기화: 커널 모드 동기화, 메모리 접근 동기화

-  반환 타입이 HANDLE이라는 것은 뮤텍스가 커널 오브젝트임을 말한다. 초기화 함수 호출이 필요 없음. CreatMutex() 호출 과정에서 필요한 모든 초기화가 이루어지기 때문. 뮤텍스는 누군가에 의해 획득이 가능할 때 Signaled 상태에 놓인다. WaitForSingleObject()를 임계 영역 진입을 위한 뮤텍스 획득의 용도로 사용 가능. 인자로 전달된 핸들의 커널 오브젝트가 Signaled 상태가 되어서 반환하는 경우, 해당 커널 오브젝트를 Non-Signaled 상태로 변경해 버림. (이 경우 다른 쓰레드들은 임계 영역으로의 진입이 제한됨). 임계 영역에서 일을 마친 쓰레드가 임계 영역을 빠져나오면서 ReleaseMutex() 호출하여 뮤텍스 반환. (뮤텍스는 다시 Signaled 상태가 됨 -> 다른 누군가에게 획득이 가능한 상태가 되어 쓰레드의 진입을 허용.). 리소스의 해제는 CloseHandle() 호출하면서 핸들을 반환하면 됨. 획득한 쓰레드가 직접 반환해야 함.

 

4.  세마포어(Semaphore)기반의 동기화: 커널 모드 동기화, 메모리 접근 동기화

-  카운트(Count)기능이 존재함. (임계 영역에 접근 가능한 쓰레드 개수를 조절하는 기능). CreateSemaphore()로 세마포어 오브젝트를 생성하며 생성될 때 전달인자 lInitalCount에 의해 초기 카운트가 결정됨. 카운트가 0인 경우 Non-Signaled 상태에 놓이게 되며, 1 이상인 경우 Signaled 상태에 있게 됨. 세마포어의 핸들을 인자로 전달하면서 WaitForSingleObject()를 호출할 경우, 그 값이 하나씩 감소하면서 함수를 반환함. 카운트 개수에 따라 임계 영역에 동시에 들어 갈 수 있으며, 임계 영역을 빠져 나온 쓰레드는 ReleaseSemaphore()를 호출해야 함.( 세마포어 카운트를 다시 증가시켜 줌). 다른 쓰레드가 반환해줘도 됨.

 

5. 이름있는 뮤텍스(Named Mutex)기반의 프로세스 동기화: 커널 모드 동기화, 프로세스간 동기화

-  뮤텍스에 이름을 붙여 생성할 경우. 커널 오브젝트이므로, 서로 다른 프로세스 영역에 존재하는 쓰레드가 뮤텍스를 이용해서 동기화 됨. 하지만 여기서 핸들과 핸들 테이블(커널 오브젝트와 이를 지칭하는 핸들값에 대한 정보를 담고 있는 테이블)의 소유 및 유효성에 관련하여 문제가 생길 수 있는데 뮤텍스에 붙여진 이름을 통해여 Windows가 관리하고 있는 커널 오브젝트에 접근 가능한 핸들 정보를 얻음으로써 해결함.

 

6. 이벤트(Event)기반의 동기화: 커널 모드 동기화, 실행순서 동기화

-  CreateEvent()를 통해 이벤트 오브젝트 생성.(초기에 Non-Signaled 상태로 생성). 쓰레드나 프로세스가 종료될 경우 해당 커널 오브젝트는 Signaled 상태로 자동 변경되지만 이벤트 오브젝트는 자동으로 Signaled 상태가 되지 않는다. 이벤트 오브젝트가 Signaled 상태가 되어 블로킹 상태에 있던 쓰레드가 빠져 나왔을 때, Signaled 상태 그대로라면 수동 리셋 모드(Manual-Reset 모드) 이벤트 오브젝트라는 의미이고, Non-Signaled 상태로 자동 변경되었다면 자동 리셋 모드(Auto-Reset 모드) 이벤트 오브젝트라는 의미이다. 수동 리셋 모드 이벤트는 둘 이상의 쓰레드를 동시에 깨워서 실행해야 할 때 아주 좋은 도구가 될 수 있음.

 

7.  타이머(Timer)기반의 동기화

-  정해진 시간이 지나면 자동으로 Signaled 상태가 되는 특성.

1)     수동 리셋 타이머: 가장 일반적인 타이머로서, 알람 시계 같은 것. CreateWailtableTimer()로 생성되며 타이머 오브젝트는 무조건 Non-Signaled 상태로 생성됨. SetWaitableTimer()로 알람 시간 설정.

2)     주기적 타이머: 수동 리셋 타이머에 주기적인 특성이 가해진 형태. SetWaitableTImer()의 세 번째 전달인자를 다르게 하면 됨. 중간에 타이머를 해제하고자 하는 경우에는 CancelWaitableTimer()를 사용하면 되는데 타이며를 ㅈ\소멸시키거나 할당된 자원을 반환하는 종류의 함수(CloseHandle() 호출)가 아니라는 것을 인지해야함.

 

**커널 오브젝트는 상태를 지니는데, 하나는 Signaled 상태이고, 다른 하나는 Non-Signaled 상태이다. 보통 커널 오브젝트는 Non-Signaled 상태에 놓여 있다가, 특정 상황이 되면 Signaled 상태가 된다. 이 특정 상황이라는 것은 커널 오브젝트에 의존적이다.

728x90
반응형

'서버 > 시스템 프로그래밍' 카테고리의 다른 글

동기 및 비동기 I/O  (0) 2022.08.09
Thread 관련  (0) 2022.08.05
함수 호출규약  (0) 2022.08.05
스케줄링  (0) 2022.08.05
컨텍스트 스위칭(Context Switching)  (0) 2021.09.03

+ Recent posts