Event
는 스레드 간 순위가 보장되지 않다보니, 이를 관리하기 위해 사용한다. 이를 스레드 동기화라고 한다.
Producer
클래스가 데이터를 저장하고 Consumer
클래스가 데이터를 읽는 소스코드가 있다고 가정해보자. 단순히 저장하고 읽으면 되지만, 시간이 오래 걸려 이를 동시에 작업을 시작하도록 했다.
하지만, Producer
가 데이터를 저장하기 전에 Consumer
가 데이터를 읽을 수 없기에 대기를 해야 한다. 여기서, Consumer
는 Producer
의 작업이 끝날 때까지 기다려주는데 이를 동기화라고 한다. 이 작업을 Event
객체에서 처리할 수 있다.
Event
객체는 0 혹은 1로 상태를 기억할 수 있는 커널 오브젝트이다. 생성 예시는 다음과 같다.
HANDLE handle = ::CreateEvent(NULL/*보안속성*/, FALSE/*bManualReset*/, FALSE/*binitialState*/, NULL);
첫번째 인자 : SECURITY_ATTRIBUTES
구조체로 선언된 변수의 주소값이다. 이 객체는 보안 기술자의 계정 정보를 명시해야 한다(정확히는 모르겠으니 일단 NULL로 작성해도 상관없을 듯 하다)
두번째 인자 : TRUE값을 기입하면 이벤트 정보가 계속 유지되도록 한다. FALSE값이 들어가기 전까지 TRUE로 유지되는 이벤트 객체가 만들어진다.
세번째 인자 : 이벤트 객체의 초기값을 선언한다. 현재 이벤트 객체의 상태값을 가리킨다.
네번째 인자 : 이벤트 객체에 사용할 이름을 선언한다.
그 외 주로 사용되는 소스코드는 다음과 같다.
::SetEvent(handle);
::WaitForSingleObject(handle, INFINITE);
::CloseHandle(handle);
SetEvent
: 현재 이벤트 상태값을 TRUE로 변경한다.
WaitSingleObject
: 이벤트 상태값이 TRUE가 될 때까지 기다린다(인자값으로 상태를 넣을 수 있는데, INFINITE
의 경우 무한히 대기한다)
CloseHandle
: 이벤트 핸들값을 종료한다. 이벤트를 사용하고 종료해주면 된다.
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>
#include <atomic>
#include <mutex>
#include <windows.h>
mutex m;
queue<int32> q;
HANDLE handle;
void Producer()
{
while (true)
{
unique_lock<mutex> lock(m);
q.push(100);
}
::SetEvent(handle);
//this_thread::sleep_for(100ms);
}
void Consumer()
{
while (true)
{
::WaitForSingleObject(handle, INFINITE);
unique_lock<mutex> lock(m);
if (q.empty() == false)
{
int32 data = q.front();
q.pop();
cout << data << endl;
}
}
}
int main()
{
// 커널 오브젝트
// Usage Count
// Signal (파란불) / Non-Signal (빨간불) << bool
// Auto / Manual << bool
handle = ::CreateEvent(NULL/*보안속성*/, FALSE/*bManualReset*/, FALSE/*binitialState*/, NULL);
thread t1(Producer);
thread t2(Consumer);
t1.join();
t2.join();
::CloseHandle(handle);
}
좋은 정보 감사합니다