c++/C++ 멀티스레딩 게임 서버

이벤트(Event) 동기화 메커니즘 이해하기

keepGGoing 2025. 4. 20. 21:17

이벤트는 스레드 간 동기화를 위한 커널 오브젝트로,

특히 스레드가 특정 조건이 충족될 때까지 대기해야 하는 상황에서 유용합니다.

 

아래 내용은 이벤트의 개념과 활용에 대한 정리입니다. (c++ 게임서버 강의를 듣고 정리하였습니.)

 

기본 개념

  • 이벤트: 커널에서 관리하는 동기화 객체로, Signal(초록불)/Non-Signal(빨간불) 상태를 가짐
  • 목적: 스레드 간 통신 및 동기화, 특히 무의미한 대기 상태를 방지하기 위해 사용

 

  1.  

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;
        }
    }
}

 

이벤트의 작동 원리

  1. 대기 중인 스레드(Consumer)는 이벤트가 Signal 상태가 될 때까지 대기
  2. 다른 스레드(Producer)가 이벤트를 Signal 상태로 변경
  3. 커널이 대기 중인 스레드에게 Signal 상태가 되었음을 알림
  4. 대기 중인 스레드가 깨어나 작업 수행

이벤트 유형

  1. Auto Reset Event:
    • 대기 중인 스레드가 깨어나면 자동으로 Non-Signal 상태로 변경됨
    • 한 번의 Signal에 하나의 스레드만 깨어남
  2. Manual Reset Event:
    • Signal 상태가 명시적으로 Reset 호출될 때까지 유지됨
    • 여러 스레드가 동시에 깨어날 수 있음
    •  

이벤트의 장단점

장점:

  • 무의미한 CPU 사용을 방지 (폴링 방식 대비, 폴링 방식 : 데이터의 상태 변화를 주기적으로 확인하는 방법)
  • 프로세스 간 동기화에도 사용 가능
  • 커널 수준에서 관리되어 안정적

단점:

  • 커널 모드 전환 오버헤드 발생
  • 자주 발생하는 이벤트에는 성능 저하 가능성
  • 커널 개입으로 인한 추가 복잡성

활용 시나리오

이벤트는 다음과 같은 상황에서 특히 유용합니다:

  • 간헐적으로 발생하는 조건에 대한 대기
  • 데이터가 드물게 생성되는 프로듀서-컨슈머 패턴
  • 프로세스 간 통신이 필요한 경우

일반적으로 높은 빈도로 발생하는 동기화보다는 드물게 발생하는 이벤트에 더 적합합니다.