반응형

1. 비동기 Notification의 의미

인터넷 계층

Link계층 : 물리 + 데이터링크

IP계층

TCP/UDP계층 : 송수신 버퍼가 생성된다.

응용프로그램 계층


동기화된 입력 및 출력 함수의 호출


동기화 : 함수의 호출과 행위의 시작, 함수의 리턴과 행위의 종료가 일치함.

데이터 전송 종료 :  Application -> TCP계층으로 데이터를 다 보낸 상황. send함수를 호출하면 출력버퍼로 보내고자 하는 데이터가 다 들어갔을 때의 상황. 

데이터 수신 종료 : TCP -> Application으로 데이터를 다 읽은 상황.


동기화된 데이터 입출력 과정상의 문제점


※ Host B의 버퍼가 꽉 찼을 경우에 (패킷 전송 일시 정지 요청에 의해) Host A는 패킷 전송을 하지 않고 blocking상태에 있게 된다.

※ send함수에서 패킷을 다 보냈을 경우 send함수가 리턴되어 종료된다.


비동기화 Notification

동기화 Notification

1. select 함수를 기반으로 한 서버의 구현

2. 핸들에 변화가 발생해야 리턴한다. select 함수의 리턴 시기와 핸들 변화 시기가 일치(동기)

비동기화 Notification

1. WSAEventSelect 함수를 기반으로 한 서버의 구현

2. 함수의 호출과 동시에 리턴한다. 따라서 핸들의 변화를 확인하기 위한 별도의 과정이 필요하다.


20.2 WSAEventSelect 모델 기반 서버 구현을 위한 API

구현순서


※ 소켓과 소켓을 위한 Event Object(소켓의 상태를 반영)가 쌍을 이룬다. 소켓의 변화가 다양하기 때문에 Event 객체가 따로 필요하다.

1. WSACreateEvent : Event를 편하게 이용할 수 있도록 돕는다.

2. WSAEventSelect

select함수 : 관심을 두고자 하는 핸들을 설정(설정) + 소켓의 변화(알림), 동기화 알림 함수.

WSAEventSelect : 관심을 두고자 하는 하나의 핸들을 설정만 할 수 있음.

3. WSAWaitForMultipleEvents : 소켓의 변화를 확인. nonsignaled에서 signaled로 변화할 때 리턴됨.

4. WSAEnumNetworkEvents : 소켓이 변화된 이유를 확인.


필요한 함수

WSAEVENT WSACreateEvent(void);

리턴 : manual-reset 모드, non-signaled 상태의 이벤트


int WSAEventSelect(

    SOCKET s,                       // 감시 대상이 되는 소켓

    WSAEVENT hEventObject, // 소켓의 변화를 확인하기 위한 이벤트 오브젝트의 핸들.

    long lNetowrkEvents         // 감시하고자 하는 이벤트 종류를 Bit-wise OR(|)로 묶어서 전달

);

리턴 : 성공시 0, 실패시 SOCKET_ERROR


감시하고자 하는 이벤트 종류

 이벤트 의미 
 FD_READ  수신된 데이터가 존재할 경우 
 FD_WRITE 블로킹되지 않고 데이터를 전송할 수 있는 경우 
 FD_OOB OOB 메세지 수신에 대한 이벤트
 FD_ACCEPT 연결 요청이 수신되었을 경우
 FD_CLOSE 연결 종료 요청이 수신되었을 경우


DWORD WSAWaitForMultipleEvents(

    DWORD cEvents,                           // 검사 대상의 핸들 수     

    const WSAEVENT FAR *lphEvents, // 검사 대상의 배열

    BOOL fWaitAll,                              // FALSE일 경우 하나의 배열만 변화가 있어도 리턴. TRUE면 모든 배열의 변화가 있어야 함.

    DWORD dwTimeout,                     // 타임아웃.

    BOOL fAlertable

);

여러 개의 이벤트 핸들(포인터로 배열 전달)이 signaled 상태가 되었는지 감시하는 함수.

리턴 : 실패시 WAIT_FAILED 리턴, 성공시 이벤트 발생 오브젝트 정보 리턴


int WSAEnumNetworkEvents(

    SOCKET s,                                                   // 소켓

    WSAEVENT hEventObject,                             // 이벤트가 발생한 소켓과 연결되어 있는 이벤트 오브젝트 핸들

    LPWSANETWORKEVENTS lpNetworkEvents    // 발생한 이벤트 정보와 오류 정보로 채워진 WSANETWORKEVENTS 구조체 포인터

);

이벤트 핸들이 발생한 이유를 알아내는 데 사용한다. signaled 상태의 이벤트 핸들을 nonsignaled상태로 바꿔주는 기능도 수행한다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR 리턴


발생한 이벤트 정보와 오류 정보로 채워진 WSANETWORKEVENTS 구조체

typedef struct _WSANETWORKEVENTS{

    long lNetworkEvents;

    int    iErrorCode[FD_MAX_EVENTS];

} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;


※ bind와 listen 사이의 소켓에 대해 이벤트를 만든다.

index = WSAWaitForMultipleEvents(sockTotal, hEventArray, FALSE, WSA_INFINITE, FALSE);

index = index - WSA_WAIT_EVENT_0;

여러 개의 소켓에서 변화가 일어났는 지 확인하고 소켓의 index값을 얻는다. 리턴된 index값은 가장 작은 소켓 인덱스 값이다. 

변화가 일어난 소켓이 여러개일 수 있기 때문에 각각을 for문을 통해 확인한다.


반응형
반응형

※ 커널 오브젝트가 생성될 때는 non-signaled 상태에 있다가 종료하는 경우에 signaled상태로 바뀐다.

※ nonsignaled상태이면 WaitForSingleObject가 멈추고 그렇지 않으면 통과(리턴)할 수 있다.


19-1. 쓰레드 동기화 기법의 분류

프로세스 실행의 두 가지 모드

사용자 모드(User Mode)와 커널 모드(Kernel Mode)


user mode : 시스템 리소스를 제외하고 원하는대로 사용가능. 

접근할 수 있는 메모리 공간이 제한되어 있음.

물리적 영역으로 직접 접근이 허용되지 않는다.

사용자 모드 동기화 기법 : CRITICAL_SECTION 오브젝트 사용

장점 : 프로그래밍하기 수월, 속도가 빠르다.

단점 : 커널 모드 동기화 기법에 비해 제한된 기능만 가진다.


kernel mode : 시스템 리소스를 접근할 수 있지만 시스템 콜을 통해서만 운영체제에서 직접 처리한다

시스템의 모든 메모리 영역으로 접근 가능.

시스템 리소스 : 파일, 쓰레드

시스템의 안전성을 보장하기 위해서 제공

커널 모드 동기화 기법 : Event, Semaphore, Mutex (다른 프로세스에서 접근 가능)

장점 : Deadlock 문제를 막을 수 있다. 둘 이상의 프로세스 내에 존재하는 쓰레드 간의 동기화 가능. 

단점 : 실행 속도의 저하가 발생.


19-2. CRITICAL_SECTION

동기화 관련 함수

※ lpCriticalSection : CRITICAL_SECTION 변수의 포인터

CS 초기화 : void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

CS 소유(임계영역에 들어갈 때) : void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

CS 반환(임계영역을 나올 때) : void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

CS 소멸 : void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);


커널 오브젝트의 상태

뮤텍스

signaled 상태 -> 뮤텍스 소유가 가능한 상태

non-signaled 상태 -> 뮤텍스가 이미 가지고 있는(소유되어진) 상태

세마포어

signaled 상태 -> 세마포어 카운트가 0이 아닌 경우.

non-signaled 상태 -> 세마포어 카운트가 0인 경우.


BOOL CloseHandle(HANDLE hObject);

커널 오브젝트 객체를 소멸한다. 참조카운트 1 감소.


19-3. Mutex(Mutual Exclusion)

HANDLE CreateMutex(

    LPSECURITY_ATTRIBUTES lpMutexAttributes,

    BOOL bInitialOwner,

    LPCTSTR lpName

);

뮤텍스 객체를 생성하고 참조카운트 1 증가.

리턴 : 성공시 생성된 Mutex 오브젝트 핸들, 실패시

lpMutexAttributes : 보안설정

bInitialOwner : false는 signal, true는 non-signal상태로

lpName : 객체 이름


※ WaitSingleObject함수는 뮤텍스를 가져오는(lock) 함수

BOOL ReleaseMutex(

    HANDLE hMutex

);

Mutex를 돌려주는(unlock)하는 함수.

리턴 : 성공시 TRUE 실패시 FALSE

non-signaled -> signaled


Mutex를 통한 쓰레드 동기화


19-4. Semaphore

세마포어가 0이 되어야 세마포어 오브젝트 non-signaled 상태가 된다.

HANDLE CreateSemaphore(

    LPSECURITY_ATTRIBTE lpSemaphoreAttributes,

    LONG lInitialCount,

    LONG lMaximumCount,

    LPCTSTR lpName

);

세마포어 객체를 생성하고 참조카운트 1 증가.

리턴 : 성공시 생성된 Mutex 오브젝트 핸들, 실패시

lpMutexAttributes : 보안설정

lInitialCount : 초기 세마포어값.

lMaximumCount : 세마포어의 최대값.

lpName : 객체 이름


※ WaitForSingleObject는 세마포어 값을 감소시킨다. signaled상태 -> nonsignaled상태로

BOOL ReleaseSemaphore(

    HANDLE hSemaphore,

    LONG lReleaseCount,

    LPLONG lpPreviousCount

);

리턴 : 성공시 TRUE, 실패시 FALSE

hSemaphore : 세마포어의 핸들.

lReleaseCount : 세마포어 값을 증가시킬 크기

lpPreviousCount : 이 함수를 호출하기 전에 카운트 값을 저장할 수 있다.


19-5. Event

Event 특징 : auto & manual-reset 모드의 커널 오브젝트의 생성이 가능하다.

※ 대기 중에 있는 쓰레드들을 한꺼번에 깨울 수 있다. (장점)

HANDLE CreateEvent(

    LPSECURITY_ATTRIBUTES lpEventAttributes,

    BOOL bManualReset,

    BOOL bInitialState,

    LPCTSTR lpName

);

이벤트를 생성한다.

리턴 : 성공시 생성된 Event 오브젝트 핸들. 실패시 NULL

lpEventAttributes : 보안설정

bManualReset : TRUE면 manual-reset 모드의 이벤트 생성. 

bInitialState : TRUE면 signaled 상태의 이벤트 생성, FALSE면 non-signaled 상태의 Evenet가 생성

lpName : Event에 이름을 준다.


manual-reset 모드 Event 동기화 원리

1. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -> 쓰레드 생성하면 대기상태로 생성.

2. SetEvent(hEvent);

3. NumberOfA, NumberOfOthers가 수행됨.

반응형

+ Recent posts