Concurrency Runtime
– 동기화 객체 2. ( event )
작성자: 임준환( mumbi at daum dot net )
시작하는 글
지난 글에 이어서 Concurrency Runtime 에서 제공하는 동기화 객체에 대해서 알아보도록 하겠습니다.
이번 글에서는 event 에 대해서 알아보겠습니다.
event
event 는 어떤 상태를 나타낼 수 있는 동기화 객체입니다.
event 는 어떤 공유 데이터에 대한 접근을 동기화하는 것이 아니라 실행의 흐름을 동기화합니다.
어떤 작업이 완료되기를 기다렸다가 진행될 수 있고, 어떤 상태를 외부에 알릴 수도 있습니다.
event 는 기본적으로 2가지 상태를 갖습니다. 설정된 상태( 시그널된 상태라고도 합니다. )와 설정되지 않은 상태를 가지고 있고, 플래그의 역할을 할 수 있습니다.
event 는 자신의 상태가 설정될 때까지 기다리는 기능을 가지고 있어서 실행의 흐름을 동기화할 수 있습니다.
Windows API 의 이벤트 객체와 유사합니다. 다른 점은 event 는 협조적이라는 것입니다. wait() 에 의해 대기하고 있을 때, 대기 중인 스레드 자원을 다른 작업에 사용하여 더욱 효율적인 스케쥴링을 하게 됩니다.
멤버 함수
생성자와 소멸자를 제외한 public 인 멤버 함수들에 대해 알아보도록 하겠습니다.
void set()
event 를 설정합니다.
wait() 로 기다리던 event 는 계속해서 진행하게 됩니다.
void reset()
event 를 설정하지 않습니다. 즉, 초기 상태로 되돌립니다.
size_t wait(unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE)
event 가 설정될 때까지 기다립니다.
매개변수인 _Timeout 은 기다리는 최대 시간을 지정할 수 있습니다. 기본 매개변수인 COOPERATIVE_TIMEOUT_INFINITE 는 무한대를 나타냅니다.
event 가 설정되어 기다리는 것을 멈추고 계속 진행될 때, wait() 는 0 을 반환합니다. 반면에 지정한 최대 시간을 초과하여 기다리는 것을 멈추고 계속 진행될 때는 COOPERATIVE_WAIT_TIMEOUT( 0xffffffff ) 를 반환합니다.
static size_t __cdecl wait_for_multiple(event ** _PPEvents, size_t _Count, bool _FWaitAll, unsigned int _Timeout = COOPERATIVE_TIMEOUT_INFINITE);
정적 멤버 함수로 여러 개의 event 를 기다립니다.
매개 변수인 _PPEvents 는 event 의 포인터 배열입니다.
매개 변수인 _Count 는 기다릴 event 의 개수입니다.
매개 변수인 _FWaitAll 은 지정된 event 들이 모두 설정될 때까지 기다릴 것인지 여부입니다. false 를 지정하면 하나의 event 라도 설정되면 기다리는 것을 멈추고 계속 진행됩니다.
마지막 매개 변수인 _Timeout 은 최대 시간입니다. 기본 매개 변수인 COOPERATIVE_TIMEOUT_INFINITE 는 무한대를 나타냅니다.
매개 변수 중 _FWaitAll 을 false 로 지정하고, 하나의 event 가 설정되었을 때, 설정된 event 의 _PPEvents 로 지정된 배열의 인덱스가 반환됩니다.
_FWaitAll 을 true 로 지정했을 경우에 모든 event 가 설정되었을 때에는 COOPERATIVE_WAIT_TIMEOUT 이 아닌 값이 반환됩니다.
Windows API 의 이벤트 객체를 사용할 때 함께 사용하는 WaitForMultipleObject() 와 유사합니다.
예제
Windows API 의 이벤트 객체와 어떻게 다른지 알아볼 수 있는 예제를 구현해보겠습니다.
시나리오
우선 최대 2개의 작업이 동시에 수행될 수 있도록 설정합니다.
그리고 하나의 event 를 생성한 후, 5개의 작업을 병렬로 처리합니다. 각 작업마다 생성한 event 가 설정될 때까지 기다리도록 합니다.
메인 스레드에서 1 초 후에 그 event 를 설정합니다.
같은 작업을 Windows API 의 이벤트 객체를 사용해서 구현합니다.
코드
// 코드의 출처는 msdn 입니다. #include <windows.h> #include <concrtrm.h> #include <ppl.h> #include <iostream> #include <sstream> using namespace Concurrency; using namespace std; // Demonstrates the usage of cooperative events. void RunCooperativeEvents() { // An event object. event e; // Create a task group and execute five tasks that wait for // the event to be set. task_group tasks; for (int i = 0; i < 5; ++i) { tasks.run([&] { // Print a message before waiting on the event. wstringstream ss; ss << L"\t\tContext " << GetExecutionContextId() << L": waiting on an event." << endl; wcout << ss.str(); // Wait for the event to be set. e.wait(); // Print a message after the event is set. ss = wstringstream(); ss << L"\t\tContext " << GetExecutionContextId() << L": received the event." << endl; wcout << ss.str(); }); } // Wait a sufficient amount of time for all tasks to enter // the waiting state. Sleep(1000L); // Set the event. wstringstream ss; ss << L"\tSetting the event." << endl; wcout << ss.str(); e.set(); // Wait for all tasks to complete. tasks.wait(); } // Demonstrates the usage of preemptive events. void RunWindowsEvents() { // A Windows event object. HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("Windows Event")); // Create a task group and execute five tasks that wait for // the event to be set. task_group tasks; for (int i = 0; i < 5; ++i) { tasks.run([&] { // Print a message before waiting on the event. wstringstream ss; ss << L"\t\tContext " << GetExecutionContextId() << L": waiting on an event." << endl; wcout << ss.str(); // Wait for the event to be set. WaitForSingleObject(hEvent, INFINITE); // Print a message after the event is set. ss = wstringstream(); ss << L"\t\tContext " << GetExecutionContextId() << L": received the event." << endl; wcout << ss.str(); }); } // Wait a sufficient amount of time for all tasks to enter // the waiting state. Sleep(1000L); // Set the event. wstringstream ss; ss << L"\tSetting the event." << endl; wcout << ss.str(); SetEvent(hEvent); // Wait for all tasks to complete. tasks.wait(); // Close the event handle. CloseHandle(hEvent); } int wmain() { // Create a scheduler policy that allows up to two // simultaneous tasks. SchedulerPolicy policy(1, MaxConcurrency, 2); // Attach the policy to the current scheduler. CurrentScheduler::Create(policy); wcout << L"Cooperative event:" << endl; RunCooperativeEvents(); wcout << L"Windows event:" << endl; RunWindowsEvents(); }
[ 코드1. event 와 Windows API 이벤트 객체와의 차이 ]
event 의 경우 5 개의 작업 중 동시에 2개가 수행되도록 하여 2 개의 작업이 기다리고 있을 때, 기다리는 스레드 자원은 다른 작업을 하게 됩니다. 이것이 바로 협력적인 스케쥴링입니다.
반면에 Windows API 의 이벤트 객체를 사용할 경우, 2 개의 작업이 다시 시작될 때까지 스레드 자원은 낭비를 하게 됩니다.
[ 그림1. event와 Windows API 이벤트 객체와의 차이 예제 결과 ]
마치는 글
Concurrency Runtime 에서 제공하는 동기화 객체인 event 까지 알아보았습니다. 이렇게 해서 제공하는 모든 동기화 객체를 알아보았습니다.
동기화 객체도 알아보았으니 이제 사용자 정의 message block 을 구현할 준비가 다 된 것 같습니다.
다음 글에서는 제공하는 message block 이 외에 사용자가 구현사여 사용하는 message block 에 대해서 알아보겠습니다.
'VC++ 10 Concurrency Runtime' 카테고리의 다른 글
Concurrency Runtime - 만델브로트 프랙탈 ( Mandelbrot Fractal ) 예제 (3) | 2010.08.28 |
---|---|
Asynchronous Agents Library – message block 9. ( custom ) (0) | 2010.08.24 |
Concurrency Runtime – 동기화 객체 1. ( critical_section & reader_writer_lock ) (0) | 2010.08.15 |
Asynchronous Agents Library – message block 8. ( timer ) (0) | 2010.08.12 |
Asynchronous Agents Library – message block 7. ( join & multitype_join ) (0) | 2010.08.09 |