반응형
waitForSingleObject()
이 함수는 다양한 유형의 핸들에 대한 대기 및 감시를 지원한다. 핸들이 신호를 보낼 때까지 또는 타임아웃이 발생할 때까지 블록되며, 해당 이벤트가 발생하면 반환된다.
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
- hHandle: 대기하려는 핸들(이벤트, 뮤텍스, 세마포어 등)
- dwMilliseconds: 밀리초 단위 대기 제한 시간, 0을 사용하면 바로 반환하고 INFINITE를 사용하면 무한 대기한다.
- DWORD 리턴값
- WAIT_OBJECT_0(0): 대기가 성공적으로 종료된 경우. 대상 핸들이 스레드인 경우엔 스레드가 종료된경우, 대상 핸들이 뮤텍스인 경우엔 뮤텍스 락을 획득한 경우, 대상 핸들이 이벤트인 경우엔 이벤트가 시그널 상태로 전환된 경우를 의미한다.
- WAIT_TIMEOUT(0x102): 대기 성공 종료 조건을 만족하지 않은 채 제한 시간이 초과된 경우.
- WAIT_FAILED(0xFFFFFFFF): 함수 호출 자체가 실패한 경우
waitForSingleObject () 사용 예시.
#include <Windows.h>
#include <iostream>
int main() {
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL) {
std::cerr << "Failed to create event." << std::endl;
return 1;
}
// 이벤트를 시그널 상태로 설정
SetEvent(hEvent);
// 이벤트 핸들이 시그널 상태가 될 때까지 대기
DWORD result = WaitForSingleObject(hEvent, INFINITE);
if (result == WAIT_OBJECT_0) {
std::cout << "Event occurred." << std::endl;
}
else {
std::cout << "Wait failed." << std::endl;
}
CloseHandle(hEvent);
return 0;
}
waitForMultipleObjects()
DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
- nCount: 대기할 핸들 배열의 요소 수
- lpHandles: 대기할 핸들 배열
- bWaitAll: TRUE로 설정하면 모든 핸들이 시그널 상태가 될 때까지 대기하고 ,FALSE로 설정하면 하나 이상의 핸들이 시그널 상태가 되면 리턴한다.
- dwMilliseconds: ms초 단위 대기 제한 시간. 0 또는 INFINITE 사용하면 바로 리턴하거나 무한 대기할 수 있다.
- DWORD 리턴 값 : 대기중 이벤트가 발생하면 lpHandles 배열에서 해당 이벤트 핸들의 인덱스를 반환한다. 이를 통해 어떤 이벤트가 발생했는지 확인할 수 있다.
waitForMultipleObjects() 사용 예시.
#include <Windows.h>
#include <iostream>
int main() {
HANDLE hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent1 == NULL) {
std::cerr << "Failed to create event." << std::endl;
return 1;
}
HANDLE hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent2 == NULL) {
std::cerr << "Failed to create event." << std::endl;
return 1;
}
HANDLE handles[2];
handles[0] = hEvent1;
handles[1] = hEvent2;
// 첫 번째 이벤트를 시그널 상태로 설정
SetEvent(hEvent2);
// 두 이벤트 중 하나가 발생할 때까지 대기
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (result == WAIT_OBJECT_0) {
std::cout << "Event 1 occurred." << std::endl;
}
else if (result == WAIT_OBJECT_0 + 1) {
std::cout << "Event 2 occurred." << std::endl;
}
else {
std::cout << "Wait failed." << std::endl;
}
CloseHandle(hEvent1);
CloseHandle(hEvent2);
return 0;
}
지원하는 대기 및 감시의 종류
waitForSingleObject, waitForMultipleObjects를 사용해 특정 작업이 완료될 때까지 대기할 수 있는 커널 객체 핸들에는 다음과 같은 것들이 있다.
- Thread (스레드) : CreateThread로 생성한 스레드가 실행을 마치고 종료됨
- Mutex (뮤텍스) : CreateMutex로 생성한 뮤텍스의 소유권 획득이 가능해짐
- 세마포어 (Semaphore) : CreateSemaphore로 생성한 세마포어의 카운트가 0보다 커져서 자원 사용이 가능해짐
- Event (이벤트) : CreateEvent로 생성한 이벤트가 SetEvent에 의해 signaled 상태가 됨
- Process (프로세스) : CreateProcess로 생성되어 실행 중이던 외부 프로그램이 완전히 종료됨
1. 스레드 종료 대기
CreateThread로 생성된 스레드의 핸들을 전달하여 해당 스레드가 종료될 때까지 대기한다.
스레드 종료 대기 예시.
1번 스레드에서 공유자원을 10000000만큼 증가시키고 2번 스레드에서는 1번 스레드 종료까지 대기했다가 공유자원을 2배로 증가시키는 예제
#include <windows.h>
#include <stdio.h>
int sharedResource = 0; // 공유 자원
HANDLE hThread1, hThread2;
DWORD WINAPI ThreadFunction1(LPVOID lpParam) {
// 1번 스레드: sharedResource를 증가
for (int i = 0; i < 10000000; i++) {
sharedResource++;
}
printf("Thread 1 finished. sharedResource = %d\n", sharedResource);
return 0;
}
DWORD WINAPI ThreadFunction2(LPVOID lpParam) {
// 2번 스레드: 1번 스레드가 종료될 때까지 대기
WaitForSingleObject(hThread1, INFINITE);
// 1번 스레드가 종료되면 sharedResource를 2배로 증가
sharedResource *= 2;
printf("Thread 2 finished. sharedResource = %d\n", sharedResource);
return 0;
}
int main() {
// 스레드 1 생성
hThread1 = CreateThread(NULL, 0, ThreadFunction1, NULL, 0, NULL);
if (hThread1 == NULL) {
printf("CreateThread for Thread 1 failed, error %d\n", GetLastError());
return 1;
}
// 스레드 2 생성
hThread2 = CreateThread(NULL, 0, ThreadFunction2, NULL, 0, NULL);
if (hThread2 == NULL) {
printf("CreateThread for Thread 2 failed, error %d\n", GetLastError());
return 1;
}
// 스레드 1 종료 대기
WaitForSingleObject(hThread1, INFINITE);
// 스레드 핸들 닫기
CloseHandle(hThread1);
CloseHandle(hThread2);
return 0;
}
2. 뮤텍스 또는 세마포어 대기
CreateMutex, CreateSemaphore와 같은 함수로 생성된 뮤텍스나 세마포어 핸들을 전달하여 다른 스레드나 프로세스가 해당 뮤텍스나 세마포어를 신호를 보낼 때까지 대기한다.
뮤텍스 대기 예시.
스레드를 4개만들고 WaitForSingleObject로 뮤텍스 락을 얻을 때까지 대기시켜 안전하게 공유자원에 액세스 한 뒤 뮤텍스 락을 해제해 다른 스레드가 접근할 수 있도록 하는 예제
#include <windows.h>
#include <stdio.h>
#define NUM_THREADS 4 // 테스트할 스레드 개수
// 공유 자원
int sharedResource = 0;
// 뮤텍스 핸들
HANDLE hMutex;
DWORD WINAPI ThreadFunction(LPVOID lpParam) {
for (int i = 0; i < 10000; i++) {
// 뮤텍스 락을 얻기 위해 대기
DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
// WAIT_OBJECT_0: 대기 중 signaled 상태가 되어 리턴한 경우
// WAIT_TIMEOUT : 타임아웃으로 리턴한 경우
// WAIT_FAILED : 핸들이 잘못되었거나, 시스템 오류로 리턴한 경우
if (dwWaitResult == WAIT_OBJECT_0) {
// 뮤텍스 락 획득 성공
sharedResource++; // 공유 자원을 수정
// 뮤텍스 락 해제
ReleaseMutex(hMutex);
} else {
// 뮤텍스 락 실패
printf("WaitForSingleObject failed, error %d\n", GetLastError());
}
}
return 0;
}
int main() {
// 뮤텍스 생성
hMutex = CreateMutex(NULL, FALSE, NULL);
if (hMutex == NULL) {
printf("CreateMutex failed, error %d\n", GetLastError());
return 1;
}
// 여러 개의 스레드 생성 및 실행
HANDLE hThreads[NUM_THREADS];
DWORD dwThreadIds[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++) {
hThreads[i] = CreateThread(NULL, 0, ThreadFunction, NULL, 0, &dwThreadIds[i]);
if (hThreads[i] == NULL) {
printf("CreateThread failed, error %d\n", GetLastError());
return 1;
}
}
// 스레드 종료 대기
WaitForMultipleObjects(NUM_THREADS, hThreads, TRUE, INFINITE);
// 뮤텍스 핸들 닫기
CloseHandle(hMutex);
// 스레드 핸들 닫기
for (int i = 0; i < NUM_THREADS; i++) {
CloseHandle(hThreads[i]);
}
printf("Final sharedResource value: %d\n", sharedResource);
return 0;
}
3. 이벤트 핸들 대기
CreateEvent 함수로 생성된 이벤트 핸들을 전달하여 이벤트가 시그널될 때까지 대기할 수 있다.
반응형
'프로그래밍 > C' 카테고리의 다른 글
| C/C++ ] ANSI 이스케이프 코드 시퀀스 사용해서 커서 이동 + 터미널 조작하기 (0) | 2023.12.11 |
|---|---|
| Win32 API ] 이벤트 / CreateEvent, SetEvent, ResetEvent (0) | 2023.10.31 |
| 고해상도 타이머 QueryPerformanceFrequency, QueryPerformanceCounter (0) | 2023.10.09 |
| C] strstr, strcmp, strncmp, stricmp, strnicmp 함수 구현 (0) | 2023.09.15 |
| C ] Data Types Range (0) | 2023.09.15 |