티스토리 뷰

올제 TREND/COOLture

스레드 동기화

어제, 오늘 그리고 allje 2011. 9. 2. 09:16

동기화를 하는이유?
- 멀티 스레드를 사용하는 프로그램에서 두 개 이상의 스레드가 동시에 공유데이터에 접근하는 것을 막는다.
- 스레드간의 실행순서를 정의하고 따르도록 한다.

동기화 개체
- CCriticalSection
- CMutex
- CEvent
- CSemaphore

동기화 액세스 개체
- CSingleLock
- CMultiLock

CCriticalSection
1. 같은 프로세스에 속한 스레드간의 동기화를 위해 사용한다.
2. 유저 모드에서 동작하므로, 속도가 빠르다.

ex)
CCriticalSection g_cs;

g_cs.Lock();
// Working //
g_cs.Unlock();

CMutex
1. 서로 다른 프로세스간의 동기화를 위해 사용(임계영역과 같은 기능을 하지만 속도는 조금 느림)

CMutex::CMutex( 
            BOOL bInitiallyOwn=FALSE,
            LPCTSTR lpszName=NULL,
            LPSECURITY_ATTRIBUTES lpsaAttribute=NULL

)
1. TRUE이면 뮤텍스를 생성한 스레드가 소유자가 된다.
2. 뮤텍스 부여. 서로다른 프로세스에 존재하는 스레드를 동기화 하려면 동일한 이름을 가진 뮤텍스를 지정
3. 보안 설명자와 핸들 상속 관련 구조체

ex)
#include <afxmt.h>

CMutex g_mutex(FALSE, NULL);

g_mutex.Lock();
// Working //
g_mutex.Unlock();

CEvent
1. 공유 리소스를 서로 사용할 경우 사용.
2. 하나의 스레드가 작업을 완료한 후 다른 모든 스레드에게 Event로 Locking을 해제할 경우 사용

CEvent::CEvent(
            BOOL bInitiallyOwn = FALSE,
            BOOL bManualReset = FALSE,
            LPCTSTR lpszName = NULL,
            LPSECURITY_ATTRIBUTES lpsaAttribute = NULL)
1. FALSE면 비신호(중지), TRUE면 신호 상태(런)
2. FALSE면 Lock를 하나씩 오픈, TRUE면 Lock을 한번에 다 풀어줌
3. 이벤트 이름
4. 보안 설명자와 핸들 상속 관련 구조체

ex)
#include <afxmt.h>

CEvent g_Event(TRUE,TRUE);

g_Event.Lock();
// Working //

g_Event.PulseEvent(); signaled로 갔다가 바로 non-signaled로 전환..
g_Event.SetEvent(); signaled로 세팅
g_Event.ResetEvent(); Non-signaled로 세팅

CSemaphore
1. 여러 스레드중 동시에 실행가능한 개수를 제어하는 용도로 사용.

CSemaphore::CSemaphore(
            LONG lInitialCount = 1,
            Long lMaxCount = 1,
            LPCTSTR pstrName = NULL,
            LPSECURITY_ATTRIBUTES lpsaAttributes = NULL
)
1. 동시 실행 가능한 스레드의 초기 값(0 <= lInitialCount <= lMaxCount)
2. 동시 실행 가능한 스레드의 최대 값
3. 세마포어 이름 부여
4. 보안 설명자와 핸들 상속 관련 구조체

ex)
#include <afxmt.h>

CSemaphore g_sem(2,2); // 동시에 두개의 스레드가 실행 가능하도록 설정

g_sem.Lock();
// Working //
g_sem.Unlock();

CSingleLock
CSemaphore, CMutex, CCriticalSection, CEvent를 래핑.

CSingleLock ex)
CCriticalSection g_cs;

CSingleLock lock(&g_cs);
lock.Lock();
//Working//
lock.Unlock();

일을 하던 부분에서 예외상황이 발생하여 종료됬을때, CSingleLock으로 감싸지 않은 경우 CCriticalSection은 Unlock을 수행하지 못하고, 결국 다른 스레드들도 계속 블록이 되어있게 된다. 그러나 CSingleLock으로 래핑 시켜놓고 사용을 하게된경우, CSingleLock의 소멸자가 수행이 되고 소멸자에서 Lock된것을 Unlock으로 풀어주게 된다.

CMultiLock

여러 종류의 동기화를 함께 사용할때 쓰여진다. 단, CCriticalSection은 CMultiLock으로 래핑이 안된다.

CMutex g_mutex;
CEvent g_event[2];
CSyncObject* g_pObjects[3] = {&g_mutex, &g_event[0], &g_event[1]};
CMultiLock lock(g_pObjects,3);

lock.Lock(); // 모든 스레드 객체가 signaled가 될 경우 릴리즈
or
lock.Lock(INFINITE, FALSE); // 셋충 하나만 signaled가 될 경우 릴리즈

CMultiLock::Lock(
            DWORD dwTimeOut = INFINITE,
            BOOL bWaitForAll = TRUE,
            DWORD dwWakeMask = 0
)
1. 대기 시간을 지정
2. FALSE면 어느 하나가 signaled될 경우 릴리즈, TURE면 모든 스레드가 signaled될 경우 릴리즈
3. 중지 해제를 위한 다른 조건을 지정

CMultiLock lock(g_pObjects,3);
DWORD dwResult = lock.Lock(INFINITE,3);
DWORD nIndex = dwResult - WAIT_OBJECT_0;
if( nIndex == 0 ) // g_mutex signaled.
else if( nIndex == 1) // g_event[0] signaled
else if( nIndex == 2) // g_event[1] signaled

만약 INFINITE로 설정을 안했다면 WAIT_OBJECT_0을 빼기전에 dwResult == WAIT_TIMEOUT인지 비교해야한다.




댓글
댓글쓰기 폼