CRITICAL_SECTION 동기화윈도우 운영체제 연산 방식 : dual-mode operation
유저모드 동기화 : 커널 모드 전환 안 해서 속도 빠르다
커널모드 동기화 : 기능 더 많다
CRITICAL_SECTION 기반의 동기화CRITICAL_SECTION 오브젝트
CRITICAL_SECTION 기반 동기화할 때 생성되어 활용됨CRITICAL_SECTION cs;
int main(int argc, char *argv[])
{
HANDLE tHandles[NUM_THREAD];
int i;
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 < 500000; i++)
num += 1;
LeaveCriticalSection(&cs);
return 0;
}
관련 함수
CreateMutex()CloseHandle()ReleaseMutex()WaitForSingleObject() : Mutex는 이거 반환될 때 자동으로 non-signaled 상태 되는 auto-reset 모드 커널 오브젝트임관련 함수
CreateSemaphore()CloseHandle()ReleaseSemaphore()WaitForSingleObject()Event 동기화 오브젝트는 auto-reset 모드와 manual-reset 모드 택일 가능
관련 함수
CreateEvent() : 두 번째 인자 TRUE면 manual-resetResetEvent() : non-signaled 상태로 변경SetEvent() : signaled 상태로 변경// 둘 이상의 쓰레드가 동시에 대기상태 빠져나오는 예제
int main(int argc, char *argv[])
{
HANDLE hThread1, hThread2;
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // manual-reset 모드로 non-signal 상태인 Event 생성
hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL);
hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL);
fputs("Input string: ", stdout);
fgets(str, STR_LEN, stdin);
SetEvent(hEvent);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
ResetEvent(hEvent); // 여기서 hEvent 해금하면 쓰레드1, 쓰레드2 둘 다 실행됨
CloseHandle(hEvent);
return 0;
}
unsigned WINAPI NumberOfA(void* arg)
{
int i, cnt = 0;
WaitForSingleObject(hEvent, INFINITE);
for (i = 0; str[i] != 0; i++)
{
if(str[i]=='A')
cnt++;
}
printf("Num of A: %d \n", cnt);
return 0;
}
윈도우에서 데이터 입출력할 때 send, recv로 동기화된 입출력 진행했다.
send는 출력 버퍼에 데이터 전송돼야 반환,
recv는 원하는 만큼 데이터 읽은 후에 반환.
비동기 입출력 : 함수 반환 시점과 데이터 송수신 완료시점 일치 하지 않음
Notification IO : IO 관련 상황 발생했는가?
Nofitication : IO 상태 변화 알림
IO 상태 변화
WSAEventSelect()
WSACreateEvent() : manual-reset 모드면서 non-signaled 상태인 Event 오브젝트 생성
WSACloseEvent() : Event 오브젝트 종료
WSAWaitForMultipleEvents() : 이벤트 발생 유무 확인
WSAEnumNetworkEvents() : 해당 오브젝트가 signaled된 원인 확인. 확인한 오브젝트는 non-signaled로 되돌려준다.
hSockArr[numOfClntSock] = hServSock;
hEventArr[numOfClntSock] = newEvent;
numOfClntSock++;
while(1)
{
posInfo = WSAWaitForMultipleEvents(numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE);
startIdx = posInfo - WSA_WAIT_EVENT_0;
for (i = startIdx; i < numOfClntSock; i++)
{
// hEventArr[i]이 시그널 상태인지 non block으로 확인. signal이면 WSA_WAIT_EVENT_0 반환.
int sigEventIdx = WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE);
if((sigEventIdx==WSA_WAIT_FAILED || sigEventIdx==WSA_WAIT_TIMEOUT))
{
continue;
}
else
{
// 어떤 네트워크 이벤트(FD_ACCEPT/FD_READ/FD_CLOSE)가 발생했는지 확인
sigEventIdx = i;
WSAEnumNetworkEvents(hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents);
if(netEvents.lNetworkEvents & FD_ACCEPT) // 연결 요청 시
{
if(netEvents.iErrorCode[FD_ACCEPT_BIT]!=0)
{
puts("Accept Error");
break;
}
clntAdrLen = sizeof(clntAdr);
hClntSock = accept(hSockArr[sigEventIdx], (SOCKADDR *)&clntAdr, &clntAdrLen);
newEvent = WSACreateEvent();
// 새 소켓에 이벤트 연결
WSAEventSelect(hClntSock, newEvent, FD_READ | FD_CLOSE);
hEventArr[numOfClntSock] = newEvent;
hSockArr[numOfClntSock] = hClntSock;
numOfClntSock++;
puts("connected new client...");
}
if(netEvents.lNetworkEvents & FD_READ) // 데이터 수신 시
{
if(netEvents.iErrorCode[FD_READ_BIT]!=0)
{
puts("Read Error");
break;
}
strLen = recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0);
send(hSockArr[sigEventIdx], msg, strLen, 0);
}
if(netEvents.lNetworkEvents & FD_CLOSE) // 종료 요청 시
{
if(netEvents.iErrorCode[FD_CLOSE_BIT]!=0)
{
puts("Close Error");
break;
}
WSACloseEvent(hEventArr[sigEventIdx]);
closesocket(hSockArr[sigEventIdx]);
numOfClntSock--;
CompressSockets(hSockArr, sigEventIdx, numOfClntSock);
CompressEvents(hEventArr, sigEventIdx, numOfClntSock);
}
}
}
}
WSACleanup();
return 0;
}
Event를 활용한 서버