윈도우 에서의 쓰레드의 동기화 ![]() ![]()
|
출처 : 열혈 강의 TCP/IP Programming
+ 유저 모드와 커널 모드
유저 모드
- 응용 프로그램이 실행되는 기본 모드로, 물리적인 영역으로의 접근이 허용되지 않으며, 접근할 수있는 메모리의 영역에도 제한된다.
- 응용 프로그램의 실행 모드
- 유저모드로 실행되는 과정에서는 운영체제와 관련된 메모리 영역이 보호 받는다.
- 쓰레드와 같이 커널 오브젝트의 생성을 동반하는 리소스의 생성을 위해서는 다음 모드 변환의 과정을 기본적으로 거친다.
- 유저모드 -> 커널 모드 -> 유저모드 ( 확인할 수 있는 방법이?? )
- 유저 모드에서 커널 모드는 리소스의 생성을 위한 것
- 커널 모드에서 유저 모드의 전환 : 응용 프로그램의 나머지 부분을 이어서 실행하기 위한것.
- 빈번한 모드의 변환은 성능에 영향을 줄 것.
커널 모드
- 운영체제가 실행될 때의 모드로, 메모리 뿐만 아니라 , 하드웨어의 접근에도 제한이 따르지 않는다.
- 운영체제의 실행 모드
+유저모드 동기화
- 운영체제의 도움 없이 응용 프로그램상에서 진행되는 동기화가 유저 모드 동기화.
- 속도가 빠르다.
- 운영체제의 힘을 빌리지 않기 때문에 기능은 제한적
- CRITICAL_SECTION 기반의 동기화가 그 예
+ 커널 모드 동기화
- 유저모드 동기화에 비해 제공되는 기능이 더 많다.
- DEAD_LOCK에 걸리지 않도록 타임아웃의 지정이 가능하다.
- 서로 다른 프로세스에 포함되어 있는 두 쓰레드간의 동기화가 가능하다.
- 유저모드에서는 커널 모드로 , 다시 유저모드로의 빈번한 변환이 불가피 하기 때문에 성능에 있어서의 제약이 따른다.
+DEADLOCK
- 임계영역에 진입을 대기중인, 블록킹 상태에 놓여 있는 쓰레드가 이를 빠져 나오지 못하는 상황을 의미.
+CRITICAL_SECTION 기반의 동기화 ( 유저 모드 동기화 기법 )
- CRITICAL_SECTION OBJECT 라는 것을 생성해서 이를 동기화에 활용
- 커널 오브젝트가 아님
- criticalSection 생성과 소멸 함수.
- void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
- void DeleteCriticalSection(LPCRITICAL-SECTION lpCriticalSection);
- void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
- void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
criical_section 획득 및 반납 함수.
void SyncCS_WinMain(int argc, TCHAR* argv[])
{
_tprintf(_T("SyncCS_WinMain\n"));
HANDLE tHanles[NUM_THREAD];
int i;
InitializeCriticalSection(&cs);
for(i = 0; i < NUM_THREAD; i++)
{
if(i%2)
tHanles[i] = (HANDLE)_beginthreadex(NULL, 0 , threadDec, NULL, 0 , NULL);
else
tHanles[i] = (HANDLE)_beginthreadex(NULL, 0 , threadInc, NULL, 0 , NULL);
}
WaitForMultipleObjects(NUM_THREAD, tHanles, TRUE, INFINITE);
DeleteCriticalSection(&cs);
_tprintf(_T("result : %lld\n"), num );
}
unsigned WINAPI threadInc(void *arg)
{
EnterCriticalSection(&cs);
int i =0;
_tprintf(_T("threadinc\n"));
for(i = 0; i < 5; i++)
{
num += 1;
_tprintf(_T("threadInc num %d\n"), num);
}
LeaveCriticalSection(&cs);
return 0;
}
unsigned WINAPI threadDec(void *arg)
{
EnterCriticalSection(&cs);
int i =0;
_tprintf(_T("threaddec\n"));
for(i = 0; i < 5; i++)
{ num -= 1; _tprintf(_T("thread dec num %d\n"), num); }
LeaveCriticalSection(&cs);
return 0;
}
커널 모드 동기화
+ Mutex(Mutual Exclusion ) 오브젝트 동기화
#include HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAtrributes, BOOL InitialOwner, LPCTSTR lpName);
-> 성공시 생성된 Mutex 오브젝트 핸들, 실패시 NULL 반환
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
BOOL CloseHandle(HANDLE hObject);
BOOL ReleaseMutex(HANDLE hMutex);
- Mutex는 소유되었을 때 non-signaled 상태가 되고, 반납되었을때 signal 상태가 되는 커널 오브젝트이다.
- WaitForSingleObject(hMutex, INFINITE)
- // 임계 영역 시작.
- RelaseMutex(hMutex); // 임계 영역 끝
+ 세마 포어 오브젝트 기반 동기화
- 리눅스의 바이너리 세마포어와 비슷하며 세마포어 커널 오브젝트에 등록이 된다.
- CreateSemaphore(LPSECRITY_ATTRIBUTES lpSemaphoreAttributes, LONG lIntialCount , LONG lMaxiumCount, LPCTSTR lpName);
- 세마 포어 값이 0인 경우 non-signal 상태가 되고, 0 보다 큰 경우 signal 상태가 되는 특성을 이용해서 동기화가 진행
- 매개변수 maximCount를 3으로 전달하면, 세 개의 쓰레드가 동시에 임계 영역에 진입하는 유형의 동기화도 가능하다.
- BOOL RealseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviosCount);
- WaitForSingleObject(hSemaphore, INFINITE); // 임계 영역의 시작
- RelaseSemaphore(hSemaphore, 1, NULL ); // 임계 영역의 끝
static int num;
static HANDLE semOne;
static HANDLE semTwo;
void SyncSema_WinMain(int argc, TCHAR* argv[])
{
_tprintf(_T("SyncSema_WinMain\n"));
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);
}
unsigned WINAPI Read(void *arg)
{
int i =0;
//_tprintf(_T("threadRead\n"));
for(i = 0; i < 5; i++)
{
WaitForSingleObject(semTwo, INFINITE);
_fputts(_T("InputNum :"),stdout);
_tscanf(_T("%d"),&num);
ReleaseSemaphore(semOne, 1, NULL);
}
return 0;
}
unsigned WINAPI Accu(void *arg)
{
int i , sum = 0;
for(i = 0; i < 5; i++)
{
WaitForSingleObject(semOne, INFINITE);
sum+=num;
_tprintf(_T("threadAcc sum : %d i :%d\n"), sum , i);
ReleaseSemaphore(semTwo, 1, NULL);
}
_tprintf(_T("threadAcc sum : %d \n"), sum);
return 0;
}
+Event 오브젝트 기반 동기화
HANDLE CreateEvent(LPSECURITY_ATTIRBUTE lpEventAttribute, BOOL bManualRest, BOOL bInitialState, LPCTSTR lpName);
- bManualReset: TRUE 가 전달되면, manual - reset모드의 Event 오브젝트가 생성되고, 이렇게 되면 WaitForSingleObject 함수가 반환된다고 해서 non-signal 상태가 되지 않는다.
- 명시적으로 오브젝트 상태를 변경해야 한다
- BOOL ResetEvent(HANDLE hEvent);
- BOOL SetEvent(HANDLE hEvent);
'SYSTEM PROGRAMMING' 카테고리의 다른 글
OVERLAPPED IO (0) | 2015.08.05 |
---|---|
비동기 (Aynchronous ) Notificaton IO 모델의 이해와 구현 (0) | 2015.08.05 |
커널 오브젝트의 두가지 상태 (0) | 2015.08.05 |
windows 에서의 thread (0) | 2015.08.05 |
쓰레드의 소멸과 멀티 쓰레드 기반의 다중 접속 서버의 구현 (0) | 2015.08.05 |