c++/C++ 멀티스레딩 게임 서버
이벤트(Event) 동기화 메커니즘 이해하기
keepGGoing
2025. 4. 20. 21:17
이벤트는 스레드 간 동기화를 위한 커널 오브젝트로,
특히 스레드가 특정 조건이 충족될 때까지 대기해야 하는 상황에서 유용합니다.
아래 내용은 이벤트의 개념과 활용에 대한 정리입니다. (c++ 게임서버 강의를 듣고 정리하였습니.)
기본 개념
- 이벤트: 커널에서 관리하는 동기화 객체로, Signal(초록불)/Non-Signal(빨간불) 상태를 가짐
- 목적: 스레드 간 통신 및 동기화, 특히 무의미한 대기 상태를 방지하기 위해 사용
Event 사용 예제 코드
// Producer 스레드: 데이터 생성 후 이벤트를 Signal 상태로 변경
void Producer() {
while(true) {
{
unique_lock<mutex> lock(m);
q.push(100);
}
::SetEvent(handle); // 이벤트를 Signal 상태로 변경
this_thread::sleep_for(100000ms);
}
}
// Consumer 스레드: 이벤트가 Signal 상태가 될 때까지 대기
void Consumer() {
while(true) {
// WaitForSingleObject: handle이 Signal 상태가 될 때까지 대기
::WaitForSingleObject(handle, INFINITE);
// Auto Reset Event이므로 깨어나자마자 Non-Signal로 변경됨
unique_lock<mutex> lock(m);
if(q.empty() == false) {
int32 data = q.front();
q.pop();
cout << data;
}
}
}
이벤트의 작동 원리
- 대기 중인 스레드(Consumer)는 이벤트가 Signal 상태가 될 때까지 대기
- 다른 스레드(Producer)가 이벤트를 Signal 상태로 변경
- 커널이 대기 중인 스레드에게 Signal 상태가 되었음을 알림
- 대기 중인 스레드가 깨어나 작업 수행
이벤트 유형
- Auto Reset Event:
- 대기 중인 스레드가 깨어나면 자동으로 Non-Signal 상태로 변경됨
- 한 번의 Signal에 하나의 스레드만 깨어남
- Manual Reset Event:
- Signal 상태가 명시적으로 Reset 호출될 때까지 유지됨
- 여러 스레드가 동시에 깨어날 수 있음
이벤트의 장단점
장점:
- 무의미한 CPU 사용을 방지 (폴링 방식 대비, 폴링 방식 : 데이터의 상태 변화를 주기적으로 확인하는 방법)
- 프로세스 간 동기화에도 사용 가능
- 커널 수준에서 관리되어 안정적
단점:
- 커널 모드 전환 오버헤드 발생
- 자주 발생하는 이벤트에는 성능 저하 가능성
- 커널 개입으로 인한 추가 복잡성
활용 시나리오
이벤트는 다음과 같은 상황에서 특히 유용합니다:
- 간헐적으로 발생하는 조건에 대한 대기
- 데이터가 드물게 생성되는 프로듀서-컨슈머 패턴
- 프로세스 간 통신이 필요한 경우
일반적으로 높은 빈도로 발생하는 동기화보다는 드물게 발생하는 이벤트에 더 적합합니다.