2015년 1월 9일 금요일

TCP/IP 소켓 프로그래밍 20강

20강은 윈도우에서의 쓰레드 동기화를 알아볼려고 한다.
이번 강은 함수가 많이 나와서 함수 소개를 주로 하겠다 ㄷㄷ

20-1 : 동기화 기법의 분류와 critical_section 동기화


윈도우에는 2가지 연산 방식 프로그램 실행방식이 있는데. 유저모드, 커널모드가 있다.

-유저모드 : 응용 프로그램이 실행되는 기본모드, 물리적인 영역으로의 접근이 허용되지 않으며 접근할 수 있는 메모리의 영역에도 제한이 따른다.
-커널모드 : 운영체제가 실행될 때의 모드로, 메모리 뿐만 아니라, 하드웨어의 접근에도 제한이 따르지 않는다.

하지만 유저모드에서 커널모드로 전환해야 하는 경우도 있다.
바로 쓰레드를 커널에게 요청할 때다.

문제는 모드를 자주 바꾸면 성능이 떨어진다는 것이다.
그래서 유저모드에서 할 수 있는 쓰레드 동기화라면
모드를 바꾸지 않고 하는 것이 더 이득이다.

먼저 유저모드의 동기화를 알아보자. 바로 "critical_section 동기화"다 .

critical_section를 줄여서 cs 오브젝트라고 표현하겠다.(절대 치기 귀찮아서 이러는게 아니다)

cs오브젝트의 초기화 및 소멸에 쓰이는 함수를 보자.

#include <windows.h>
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); (초기화)
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); (소멸)

- lpCriticalSection :Inin.... 함수에서는 cs 오브젝트의 주소 값 전달, 
                            Del.. 함수에서는 해제할 cs오브젝트 주소값 전달

DeleteCriticalSection 함수는 cs 오브젝트를 소멸하는 함수가 아니다.
cs 오브젝트가 사용하던 리소스를 소멸시키는 함수다.

다음은 cs오브젝트 열쇠의 획득 및 반납에 대한 함수를 보자.
#include <windows.h>
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); (획득)
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); (반납)

- lpCriticalSection : 획득(소유) 및 반납할 cs오브젝트의 주소 값 전달

위 함수를 이용한 소스를 보자.
#include <stdio.h>
#include <windows.h>
#include <process.h>

#define NUM_THREAD 50
unsigned WINAPI threadInc(void * arg);
unsigned WINAPI threadDes(void * arg);

long long num=0;
//cs 오브젝트 변수 설정
CRITICAL_SECTION cs;

int main(int argc, char *argv[])
{
HANDLE tHandles[NUM_THREAD];
int i;
// cs 오브젝트 초기화
InitializeCriticalSection(&cs);
//쓰레드 생성후 핸들값에 넣기
for(i=0; i<NUM_THREAD; i++)
{
if(i%2)
   tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
else
   tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
}
//둘 이상의 커널 오브젝트를 대상으로 상태 확인
WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
//리소스 해제
DeleteCriticalSection(&cs);
printf("result: %lld \n", num);
//윈도우는 메인함수가 끝나면 쓰레드도 같이 종료된다.
return 0;
}

unsigned WINAPI threadInc(void * arg)
{
int i;
//임계영역 설정
EnterCriticalSection(&cs);
for(i=0; i<50000000; i++)
num+=1;
LeaveCriticalSection(&cs);

return 0;
}
unsigned WINAPI threadDes(void * arg)
{
int i;
//임계영역 설정
EnterCriticalSection(&cs);
for(i=0; i<50000000; i++)
num-=1;
LeaveCriticalSection(&cs);

return 0;
}

20 - 2: 커널모드 동기화 기법


커널 모드는 유저 모드 보다 많은 동기화 기법을 지원한다.
대표적인 뮤텍스, 세마포어, 이벤트 기법을 알아보자.

1. 뮤텍스(Mutex) 오브젝트 기반 동기화 


뮤텍스 오브젝트 생성 함수

#include <windows.h>
HANDLE CreatMutex (LPSECURITY_ATTRIBUTES lpMutexAttributes, 
                             BOOL bInitialOwner, LPCTSTR lpName);
-> 성공시 생성된 뮤텍스 오브젝트의 핸들, 실패시 NULL 반환

-lpMutexAttributes : 보안관련 특성 정보의 전달, 디폴트 보안 설정을 위해서 NULL 전달
-bInitialOwner : true 전달시, 생성되는 뮤텍스 오브젝트는 이함수를 호출한 쓰레드의 소유가 되면서 non-signaled 상태가 된다. false 전달시 생성되는 뮤텍스 오브젝트는 소유자가 존재하지 않으며, signaled 상태로 생성된다.
-ipName : 뮤텍스 오브젝트에 이름을 부여할 때 사용된다. NULL을 전달하면 이름 없는 뮤텍스 오브젝트가 생성된다.

뮤텍스 소멸 함수

#include <windows.h>
BOOL CloseHandle(HANDLE hObject);
-> 성공시 true, 실패시 false 반환

-hObject : 소멸하고자 하는 커널 오브젝트의 핸들 전달

뮤택스 반납 함수

#include <windows.h>
BOOL ReleaseMutex(HANDLE hMutex);
-> 성공시 true, 실패시 false 반환

- hMutex : 반납할, 다시 말해서 소유를 해제할 뮤텍스 오브젝트의 핸들 전달

2. 세마포어 오브젝트 기반 동기화


세마포어 오브젝트 생성 함수

#include <windows.h>
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
                      LONG linitialCount, LONG lMaximumCount, LPCTSTR lpName);
-> 성공시 생성된 세마포어 오브젝트 핸들, 실패시, NULL 반환

-lpSemaphoreAttributes :보안관련 정보의 전달, 디폴트 보안설정을 위해서 NULL 전달
-linitialCount : 세마포어의 초기값 설정, 매개변수 lMaximumCount에 전달된 값보다 크면 안되고 , 0 이상이여야 함
-linitialCount : 최대 세마포어 값을 지정한다. 1을 지정하면 세마포어 값이 0, 또는 1이 되는 바이너리 세마포어가 구성된다.
-lpName : 세마포어 오브젝트에 이름을 부여할 때 사용한다. NULL을 전달하면 이름없는 세마포어 오브젝트가 된다.

세마포어 오브젝트 반납 함수

#include <windows.h>
Bool ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, 
                                     LPLONG lpPreviousCount);
-> 성공시 TRUE, 실패시 FALSE 반환

-hSemaphore : 반납할 세마포어 오브젝트 핸들 전달
-lReleaseCount : 반납은 세마포어 값의 증가를 의미하는데, 이 매개변수를 통해서 증가되는 값의 크기를 지정할 수 있다. 그리고 이로 인해서 세마포어의 최대 값을 넘어서게 되면, 값은 증가하지 않고 fales 가 반환된다.
-lpPreviousCount : 변경 이전의 세마포어 값 저장을 위한 변수의 주소 값 전달, 불필요하다면 NULL 전달

3. 이벤트 오브젝트 기반 동기화


이벤트 오브젝트 생성에 사용되는 함수

#include<windows.h>
HANDLE CreateEvent (LPSECURITY_ATTRIBUTES lpEventAttributes, 
                         BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);
-> 성공시 생성된 이벤트 오브젝트의 핸들, 실패시 NULL 반환
-lpEventAttributes : 보안 관련 정보의 전달, 디폴트 보안설정을 위해서 NULL 전달
-bManualReset : true 전달시 manual-reset 모드 이벤트, false 전달시 auto-reset 모드 이벤트 오브젝트 생성
- bInitialState : true 전달시 singnaled 상태의 이벤트 오브젝트 생성, false 전달시 non-signaled 상태의 이벤트 오브젝트 생성
-lpName : 이벤트 오브젝트에 이름을 부여할 때 사용된다. NULL을 전달하면 이름없는 이벤트 오브젝트가 생성된다.

명시적으로 오브젝트 상대를 변경하는 함수

#include <windows.h>
BOOL ResetEvent(HANDLE hEvent); //non-signaled
BOOL setEvent(HANDLE hEvent); //signaled
-> 성공시 true, 실패시 false 반환

아오 몸이 안좋으니깐 이거 치는 것도 꽤 힘들다 ㅠㅠ
윈도우 함수는 왜이리 대소문자로 왔다갔다해야하는지,........
이름이 너무 긴게 많아!!

원래는 여기 소스도 올려서 확인해봐야 하는데
내 몸상태가 영 나쁘니....
소스 코드를 직접 다운 받아 해보자 /엉엉/
소스 코드 다운 받기

댓글 없음:

댓글 쓰기