Event

난 소중하니 직원한테 부탁 (갑질메타)

예제

mutex m;
queue<int32> q;

void Producer()
{
    while(true)
    {
        {
            unique_lock<mutex> lock(m);
            q.push(100);
        }
        
        this_thread::sleep_for(10000ms);
    }
    
}

void Consumer()
{
    while(true)
    {
        {
            unique_lock<mutex> lock(m);
            if (q.empty() == false)
            {
                int32 data = q.front();
                q.pop();
                cout << data << endl;
            }
        }
    }
}

int main()
{
    thread t1(Producer);
    thread t2(Consumer);
    
    t1.join();
    t2.join();
    
    return 0;
}
  • 생산자(Producer) 쓰레드는 10초 마다 한번씩 생산하고, 소비자(Consumer) 쓰레드는 바쁜 대기를 통해 계속해서 CPU 코어를 점유함.
  • 한 번 데이터를 소비하기 위해 10초동안 코어를 점유하는 것은 너무나 비효율적임.
  • 큐에 데이터가 들어올때 알려주는 무언가가 있으면 좋을 것 같다. => Event

Create Event

mutex m;
queue<int32> q;

void Producer()
{
    while(true)
    {
        {
            unique_lock<mutex> lock(m);
            q.push(100);
        }
        
        ::SetEvent(handle); //Event의 상태를 Signal로 변경
        
        this_thread::sleep_for(10000ms);
    }
    
}

void Consumer()
{
    while(true)
    {
        ::WaitForSingleObject(handle, INFINITE); //무한 대기 -> 초록불일때까지 기다림.
        //auto 옵션이므로 여기서 다시 Signal이 빨간불로 바뀜.
        //만약 manual 옵션이라면 ::ResetEvent(handle); 추가
        {
            unique_lock<mutex> lock(m);
            if (q.empty() == false)
            {
                int32 data = q.front();
                q.pop();
                cout << data << endl;
            }
        }
    }
}

HANDLE handle; //생산자, 소비자에서 사용 가능하게끔 전역으로 선언

int main()
{
    //커널 오브젝트
    handle = ::CreateEvent(NULL/*보안속성*/, FALSE/*auto reset*/, FALSE/*초기 상태*/, NULL/*이름*/);
    
    thread t1(Producer);
    thread t2(Consumer);
    
    t1.join();
    t2.join();
    
    ::CloseHandle(handle); //사용이 끝난 Handle은 수거를 하는 것이 바람직함.
    return 0;
}

HANDLE CreateEventW(LPSECURITY lpEventAttributes, BOOL bManualReset, Bool bInitialState, LPCWSTR lpName)

  • Event는 커널에서 만들어주기 때문에 커널 오브젝트라고도 불린다.
    • 커널에서 관리하는 오브젝트다.
    • Usage Count : 해당 오브젝트를 사용중인 프로세스나 쓰레드의 수. 커널 오브젝트가 공통으로 가진다.
    • Signal / Non-Signal : 파란불, 빨간불 << bool
    • Auto / Manual : 예제에선 Auto
  • HANDLE은 int와 같은 숫자를 의미한다. ex)10, 20, 33, …
    • 일종의 번호표
    • 다른곳에서 사용 가능
  • 유저모드 <-> 커널모드 간 이동 떄문에 오버헤드가 발생함
    • 굉장히 자주 발생하는 작업에는 부적절하다.

그러나 이 코드에는 문제점이 존재함. 문제점은 다음 ConditionVariable에서 알아보자.