쓰레드 동기화 오브젝트
(Thread Synchronization Objects)
쓰레드가 2개 이상 실행될 때 여러가지 변수 가있습니다.
하나의 공유자원(예를들어 동시에 접근하는 변수) 에 접근할 때, 파일 입출력 이나 디바이스I/O작업을 할 때 동기화 오브젝트가 필요합니다.
동기화 오브젝트 없이 쓰레드가 공유 자원을 사용할 때 공유자원이 원치 않은 값이 될수 있고, I/O작업 시 쓰레드가 I/O작업이 끝날 때 까지 무한정 블로킹(blocking : 특정 함수가 리턴 될 때 까지 기다림)현상이 발생할 수 있습니다.
동기화 오브젝트를 사용하여 다중 쓰레드에서 어떻게 안전 하게 공유자원에 접근하고 다른 쓰레드간의 실행 순서등을 조작하는지에 대해 알아 보겠습니다.
동기화 오브젝트는 유저 모드와 커널 모드로 분류할 수 있습니다.
유저 모드
유저 모드는 현재 프로세스/쓰레드 내의 상태를 말합니다.
유저모드에서는 커널 오브젝트(프로세스, 파일, 디바이스 등)으로 바로 접근을 할 수 없고, 커널 오브젝트로 접근 시 시스템에 의해 변환 작업이 이루어집니다.
이런 변환 작업은 시간을 많이 걸리는 작업이기 때문에 유저 모드가 커널 모드 보다 속도가 빠릅니다.
유저 모드 동기화 방법은 코드레벨에서 동기화 하는 방법을 이야기 합니다.
유저모드에서 동기화는 사용하기 쉽고 커널 모드 동기화 함수들에 비해 속도가 빠른 장점이 있지만 커널 오브젝트(파일 I/O, 프로세스, 쓰레드 등)의 동기화는 불가능하다는 단점이 있습니다.
Interlocked
Interlocked 함수들은 다중 쓰레드에서 공유변수들을 안전하게 1씩 증가/감소, 특정값을 증가 , 비트 연산을 할 수 있습니다.
Intlocked 함수는 사용하기 쉬우므로 길게 설명은 하지 않겠습니다.
아래 사이트를 참조하시길 바랍니다.
http://msdn2.microsoft.com/en-us/library/ms686360(VS.85).aspx
크리티컬 섹션(CRITICAL SECTION)
크리티컬 섹션은 특정 코드영역을 쓰레드가 동시에 실행되는 것을 막아 줍니다.
아래는 크리티컬 섹션 관련 함수들입니다.
크리티컬 섹션 오브젝트를 삭제 합니다. | |
크리티컬 섹션 오브젝트를 초기화 합니다. | |
크리티컬 섹션 오브젝트를 초기화 하고 스핀 카운트를 설정합니다. | |
크리티컬 섹션을 초기화하고 스핀카운트 설정, 부가기능을 설정합니다. | |
크리티컬 섹션 오브젝트 권한을 해제합니다.. | |
특정 크리티컬 섹션 오브젝트 스핀카운트를 설정합니다. | |
블로킹(Wait) 되지 않고 크리티컬 섹션 오브젝트의 권한을 요청합니다. |
InitializeCriticalSectionAndSpinCount 함수는 스핀 카운트를 두어서 쓰레드가 크리티컬 섹션 오브젝트를 획득하지 못하면 Wait상태로 일정 시간(스핀카운트) 루프를 돌아 크리티컬 섹션오브젝트가 해제 되었는지 체크합니다.
해제되지 않았으면 Sleep하게 됩니다.
이 함수는 멀티 프로세서 환경에서만 유효하며, 스핀카운터는 4000을 추천(Windows Via C/C++)하지만 자신의 환경에서 값을 바꾸어 가며 테스트 해보길 권장합니다.
#include <Windows.h> CRITICAL_SECTION g_cs;
//크리티컬 섹션 오브젝트를 초기화 합니다. void InitCriticalSection() { InitializeCriticalSection(&g_cs); }
unsigned _stdcall CallThreadHandlerProc(void *pThreadHandler) { while (bExit == FALSE) { if(TryEnterCriticalSection(&g_cs)) { //쓰레드 작업을 수행 합니다. //수행 하고 LeaveCriticalSection 함수를 호출 //하여 크리티컬섹션 오브젝트를 해제합니다.
LeaveCriticalSection(&g_cs); } else { //크리티컬 섹션 오브젝트 획득에 실패시 수행할 // 작업을 선언합니다. //SwitchToThread함수를 호출하여 다른 쓰레드로 // 스위칭 합니다. SwitchToThread(); } } DWORD exitCode; GetExitCodeThread(InputThrd, &exitCode); _endthreadex(exitCode); return 0; } |
**Sleep() 함수와 SwitchToThread()함수는 디스패쳐가 다른 쓰레드로 스케쥴 하도록 합니다.
차이점은 Sleep()함수는 현재 쓰레드보다 우선순위가 같거나 높은 쓰레드가 없으면 쓰레드 전체를 리스케쥴링(rescheduling)합니다.
Slim Reader/Writer Locks
Slim reader/writer (SRW) locks 는 하나의 프로세스내의 쓰레드들이 공유자원을 동기화 할수 있습니다.
아주 작은 메모리를 차지하면서 속도도 빠릅니다.
Reader 쓰레드는 공유자원을 읽고 Writer 쓰레드는 공유자원에 쓰기 작업을 할수 있습니다.
다중 쓰레드가 공유자원을 읽고 쓰기를 할 때, 크리티컬 섹션과 뮤텍스 같은 상호배제 오브젝트(exclusive locks)들은 reader 쓰레드는 계속 돌고 writer 쓰레드는 거의 돌지 못하면 병목현상(bottle neck)이 발생 할 수 있습니다.
SRW locks는 공유자원에 접근 할수 있는 두가지 모드를 제공합니다. :
· Shared mode : 읽는 작업을 하는 쓰레드가 여러 개일 때 공유자원을 읽기 전용으로 접근할 수 있도록 해서 동시 다발적으로 작업을 할수 있도록 합니다. 만약 읽는 작업이 쓰는 작업을 초과 할 경우, 성능과 처리량은 크리티컬 섹션과 동일하게 됩니다.
· Exclusive mode : 읽기/쓰기 쓰레드는 하나의 쓰레드만 접근 할 수 있습니다. Exclusive mode로 락이 걸려지면 다른 쓰레드들은 공유자원에 접근할 수 없습니다.
하나의 SRW lock은 두가지 모드를 동시에 가질수 있습니다. 읽는 쓰레드는 Shared mode로 쓰는 쓰레드는 Exclusive mode로 작업을 할 수 있습니다. 어떤 쓰레드가 소유권을 먼저 가질지는 알수 없습니다. SRW Locks는 공정하거나 선입선출(First In First Out : FIFO)방식이 아닙니다.
SRW lock은 포인터 크기를 가집니다. 장점은 속도가 빠르고 lock상태의 변환이 빠르다는 것 입니다.
단점은 아주 작은 상태 정보만 저장이 되어 재귀적으로 SRW locks를 가질 수 없습니다. 또 Shared Mode인 쓰레드가 Shred Mode로 변환 될수 없습니다.
SWR Locks는 Windows Server 2008,Vista 에서만 사용이 가능합니다.
아래는 SRW lock 함수들 입니다.
SRW lock function | Description |
SRW lock을 exclusive mode로 얻습니다. | |
SRW lock을 shared mode로 얻습니다. | |
SRW lock을 초기화 합니다. | |
exclusive mode인 SRW lock을 해제 합니다. | |
shared mode인 SRW lock을 해제 합니다. | |
SRW작업이 완료 될때까지 Sleep 합니다. |
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=8026&ref=8026