同期データ構造

同時実行ランタイムには、複数のスレッドから共有データへのアクセスを同期するためのデータ構造がいくつか用意されています。 これらのデータ構造は、頻繁に変更する共有データがある場合に便利です。 クリティカル セクションなどの同期オブジェクトは、共有リソースが使用できるようになるまで他のスレッドを待機させます。 したがって、このようなオブジェクトを使用して、頻繁に使用されるデータへのアクセスを同期すると、アプリケーションのスケーラビリティが低下する可能性があります。 並列パターン ライブラリ (PPL) に用意されている Concurrency::combinable クラスを使用すると、同期を行わなくても、複数のスレッド間または複数のタスク間でリソースを共有できます。 combinable クラスの詳細については、「並列コンテナーと並列オブジェクト」を参照してください。

セクション

ここでは、次の型の非同期メッセージ ブロックについて詳しく説明します。

  • critical_section

  • reader_writer_lock

  • scoped_lock および scoped_lock_read

  • event

critical_section

Concurrency::critical_section クラスは、他のタスクよりも優先されるのではなく他のタスクに処理を譲る、協調的な相互排他オブジェクトを表します。 クリティカル セクションは、複数のスレッドが共有データへの排他的な読み取り/書き込みアクセスを行う必要がある場合に便利です。

critical_section クラスは再入不可能です。 既にロックを所有しているスレッドで呼び出された場合、Concurrency::critical_section::lock メソッドは Concurrency::improper_lock 型の例外をスローします。

メソッドおよび機能

次の表に、critical_section クラスで定義されている重要なメソッドを示します。

メソッド

説明

lock

クリティカル セクションを取得します。 呼び出し元のコンテキストは、ロックを取得するまでブロックされます。

try_lock

クリティカル セクションの取得を試みますが、ブロックは行いません。

unlock

クリティカル セクションを解放します。

[ページのトップへ]

reader_writer_lock

Concurrency::reader_writer_lock クラスは、共有データへのスレッド セーフな読み取り/書き込み操作を提供します。 複数のスレッドが共有リソースに対して同時読み取りアクセスを行う必要があるが、その共有リソースへの書き込みはほとんど行わない場合、リーダー/ライター ロックを使用します。 このクラスは、1 つのオブジェクトに対する書き込みを、常に 1 つのスレッドだけに許可します。

critical_section オブジェクトは共有リソースへの排他アクセスを取得することにより同時読み取りアクセスを実行できなくするため、reader_writer_lock クラスは critical_section クラスよりもパフォーマンスが優れています。

reader_writer_lock クラスは、critical_section クラスと同様に、他のタスクよりも優先されるのではなく他のタスクに処理を譲る、協調的な相互排他オブジェクトを表します。

共有リソースへの書き込みを行う必要があるスレッドがリーダー/ライター ロックを取得すると、そのリソースにアクセスする必要がある他のスレッドは、ライターがロックを解放するまでブロックされます。 reader_writer_lock クラスは、待機中のリーダーのブロックを解除する前に待機中のライターのブロックを解除する書き込み優先ロックの 1 つです。

critical_section クラスと同様に、reader_writer_lock クラスは再入不可能です。 既にロックを所有しているスレッドで呼び出された場合、Concurrency::reader_writer_lock::lock メソッドおよび Concurrency::reader_writer_lock::lock_read メソッドは improper_lock 型の例外をスローします。

注意

reader_writer_lock クラスは再入可能ではないので、読み取り専用ロックをリーダー/ライター ロックにアップグレードしたり、リーダー/ライター ロックを読み取り専用ロックにダウングレードしたりすることはできません。 いずれかの操作を実行すると、未指定の動作が発生します。

メソッドおよび機能

次の表に、reader_writer_lock クラスで定義されている重要なメソッドを示します。

メソッド

説明

lock

ロックへの読み取り/書き込みアクセスを取得します。

try_lock

ロックへの読み取り/書き込みアクセスの取得を試みますが、ブロックは行いません。

lock_read

ロックへの読み取り専用アクセスを取得します。

try_lock_read

ロックへの読み取り専用アクセスの取得を試みますが、ブロックは行いません。

unlock

ロックを解放します。

[ページのトップへ]

scoped_lock および scoped_lock_read

critical_section クラスおよび reader_writer_lock クラスは、相互排他オブジェクトの操作方法を簡素化する、入れ子になったヘルパー クラスを提供します。 これらのヘルパー クラスはスコープ ロックと呼ばれます。

critical_section クラスには Concurrency::critical_section::scoped_lock クラスが含まれています。 このクラスのコンストラクターは指定された critical_section オブジェクトへのアクセスを取得し、デストラクターはそのオブジェクトへのアクセスを解放します。 reader_writer_lock クラスには Concurrency::reader_writer_lock::scoped_lock クラスが含まれています。このクラスは critical_section::scoped_lock に似ていますが、指定された reader_writer_lock オブジェクトへの書き込みアクセスを管理する点が異なります。 同様に、reader_writer_lock クラスには Concurrency::reader_writer_lock::scoped_lock_read クラスが含まれています。 このクラスは、指定された reader_writer_lock オブジェクトへの読み取りアクセスを管理します。

スコープ ロックは、critical_section オブジェクトおよび reader_writer_lock オブジェクトを手動で操作する場合にいくつかの利点があります。 通常、スコープ ロックはスタック上に割り当てます。 相互排他オブジェクトが破棄されると、スコープ ロックはそのオブジェクトへのアクセスを自動的に解放します。したがって、基になるオブジェクトのロックを手動で解除する必要はありません。 これは、関数に複数の return ステートメントが含まれる場合に便利です。 また、スコープ ロックは、例外セーフなコードを記述するのにも役立ちます。 throw ステートメントによってスタックがアンワインドされるとアクティブなスコープ ロックのデストラクターが呼び出されるため、相互排他オブジェクトが常に正しく解放されます。

注意

critical_section::scoped_lockreader_writer_lock::scoped_lock、および reader_writer_lock::scoped_lock_read の各クラスを使用する場合は、基になる相互排他オブジェクトへのアクセスを手動で解放しないでください。 これを行うと、ランタイムが無効な状態になる可能性があります。

event

Concurrency::event クラスは、シグナル状態または非シグナル状態にすることができる同期オブジェクトを表します。 共有データへのアクセスの保護を目的とする同期オブジェクト (クリティカル セクションなど) とは異なり、イベントは実行のフローを同期します。

event クラスは、1 つのタスクが別のタスクのための作業を完了した場合に使用すると便利です。 たとえば、1 つのタスクが別のタスクに対して、ネットワーク接続またはファイルからのデータの読み取りを完了したことを通知できます。

メソッドおよび機能

次の表に、event クラスで定義されている重要なメソッドをいくつか示します。

メソッド

説明

wait

イベントがシグナル状態になるのを待機します。

set

イベントをシグナル状態に設定します。

reset

イベントを非シグナル状態に設定します。

wait_for_multiple

複数のイベントがシグナル状態になるのを待機します。

event クラスの使用方法の例については、「同期データ構造と Windows API の比較」を参照してください。

[ページのトップへ]

関連項目