同期データ構造と Windows API の比較
ここでは、同時実行ランタイムが提供する同期データ構造と Windows API が提供する同期データ構造の動作を比較します。
同時実行ランタイムが提供する同期データ構造は、協調スレッド処理モデルに従います。協調スレッド処理モデルでは、同期プリミティブは処理リソースを他のスレッドに明示的に譲渡します。これはプリエンプティブ スレッド処理モデルとは異なります。プリエンプティブ スレッド処理モデルでは、スケジューラまたはオペレーティング システムを制御することで、処理リソースを他のスレッドに転送します。
critical_section
Concurrency::critical_section クラスのような Windows CRITICAL_SECTION 、1 つのプロセスのスレッドによってのみ使用できるために構造化します。Windows API のクリティカル セクションの詳細については、「Critical Section Objects (クリティカル セクション オブジェクト)」を参照してください。
reader_writer_lock
Concurrency::reader_writer_lock クラスは、Windows のスリムなリーダー/ライター (SRW) ロックと似ています。類似点と相違点を次の表に示します。
機能 |
reader_writer_lock |
SRW ロック |
---|---|---|
再入不可能 |
○ |
○ |
リーダーをライターに昇格 (アップグレード サポート) |
X |
X |
ライターをリーダーに降格 (ダウングレード サポート) |
X |
X |
書き込み優先ロック |
○ |
X |
ライターへの FIFO アクセス |
○ |
X |
SRW ロックの詳細については、プラットフォーム SDK の「Slim Reader/Writer (SRW) Locks (スリム リーダー/ライター (SRW) ロック)」を参照してください。
event
Concurrency::event クラス無名、Windows 手動リセット イベントのようになります。ただし、event オブジェクトは協調して動作しますが、Windows イベントはプリエンプティブに動作します。Windows イベントの詳細については、「イベント オブジェクト」を参照してください。
例
Description
event クラスと Windows イベントの相違点をより詳しく理解するために、次の例について考えてみましょう。この例により、スケジューラは最大で 2 つの同時タスクを作成した後、event クラスと Windows 手動リセット イベントを使用する 2 つの類似した関数を呼び出すことができます。各関数は、まず共有イベントがシグナル状態になるのを待機する複数のタスクを作成します。次に、実行中のタスクに制御を渡し、イベントに通知します。その後、各関数はシグナル状態イベントを待機します。
コード
// event-comparison.cpp
// compile with: /EHsc
#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();
}
コメント
この例では、次のサンプル出力が生成されます。
Cooperative event:
Context 0: waiting on an event.
Context 1: waiting on an event.
Context 2: waiting on an event.
Context 3: waiting on an event.
Context 4: waiting on an event.
Setting the event.
Context 5: received the event.
Context 6: received the event.
Context 7: received the event.
Context 8: received the event.
Context 9: received the event.
Windows event:
Context 10: waiting on an event.
Context 11: waiting on an event.
Setting the event.
Context 12: received the event.
Context 14: waiting on an event.
Context 15: received the event.
Context 16: waiting on an event.
Context 17: received the event.
Context 18: waiting on an event.
Context 19: received the event.
Context 13: received the event.
event クラスは協調して動作するため、イベントがシグナル状態になるのを待機している場合、スケジューラは処理リソースを別のコンテキストに再割り当てすることができます。したがって、event クラスを使用するバージョンで、より多くの作業が実行されます。Windows イベントを使用するバージョンでは、待機中の各タスクは次のタスクが開始される前にシグナル状態になる必要があります。
タスクの詳細については、「タスクの並列化 (同時実行ランタイム)」を参照してください。