次の方法で共有


マルチスレッド アパートメント

マルチスレッド アパートメント モデルでは、フリー スレッドとして初期化されたプロセス内のすべてのスレッドが 1 つのアパートメントに存在します。 そのため、スレッド間でマーシャリングする必要はありません。 COM はこのモデルでウィンドウ メッセージを使用しないため、スレッドはメッセージを取得してディスパッチする必要はありません。

マルチスレッド アパートメント内のオブジェクトのメソッドの呼び出しは、アパートメント内の任意のスレッドで実行できます。 呼び出しのシリアル化はありません。多くの呼び出しは、同じメソッドまたは同じオブジェクトに対して同時に発生する可能性があります。 マルチスレッド アパートメントで作成されたオブジェクトは、他のスレッドからのメソッドの呼び出しをいつでも処理できる必要があります。

オブジェクトの呼び出しはいかなる方法でもシリアル化されないため、マルチスレッド オブジェクトコンカレンシーは最高のパフォーマンスを提供し、クロススレッド、クロスプロセス、およびマシン間呼び出しにマルチプロセッサ ハードウェアの利点を最大限に活用します。 ただし、これは、オブジェクトのコードがインターフェイス実装で同期を提供する必要があることを意味します。通常は、イベント オブジェクト、クリティカル セクション、ミューテックス、セマフォなどの同期プリミティブを使用します。これについては、このセクションで後述します。 さらに、オブジェクトはアクセスするスレッドの有効期間を制御しないため、スレッド固有の状態をオブジェクト (スレッド ローカル ストレージ内) に格納することはできません。

マルチスレッド アパートメントの同期に関する重要な考慮事項を次に示します。

  • COM では、シングル スレッド アパートメントに対してのみ呼び出し同期が提供されます。
  • マルチスレッド アパートメントは、(同じスレッドで) 呼び出しを行っている間は呼び出しを受け取りません。
  • マルチスレッド アパートメントは、入力同期呼び出しを行うことはできません。
  • 非同期呼び出しは、マルチスレッド アパートメントの同期呼び出しに変換されます。
  • メッセージ フィルターは、マルチスレッド アパートメント内のどのスレッドにも呼び出されません。

スレッドをフリー スレッドとして初期化するには、COINIT_MULTITHREADEDを指定 CoInitializeExを呼び出します。 インプロセス サーバースレッドの詳細については、「In-Process サーバースレッドの問題を参照してください。

複数のクライアントは、フリー スレッドをサポートするオブジェクトを異なるスレッドから同時に呼び出すことができます。 フリー スレッドのアウトプロセス サーバーでは、COM は RPC サブシステムを介してサーバー プロセス内にスレッドのプールを作成し、クライアント呼び出し (または複数のクライアント呼び出し) をこれらのスレッドによっていつでも配信できます。 アウトプロセス サーバーも、そのクラス ファクトリに同期を実装する必要があります。 フリー スレッドのインプロセス オブジェクトは、クライアントの複数のスレッドから直接呼び出しを受け取ることができます。

クライアントは、複数のスレッドで COM 作業を実行できます。 すべてのスレッドは、同じマルチスレッド アパートメントに属します。 インターフェイス ポインターはマルチスレッド アパートメント内のスレッドからスレッドに直接渡されるため、インターフェイス ポインターはスレッド間でマーシャリングされません。 メッセージ フィルター (IMessageFilterの実装) は、マルチスレッド アパートメントでは使用されません。 クライアント スレッドは、アパートメント外のオブジェクトに対して COM 呼び出しを行うと中断され、呼び出しが戻ったときに再開されます。 プロセス間の呼び出しは、RPC によって引き続き処理されます。

フリー スレッド モデルで初期化されたスレッドは、独自の同期を実装する必要があります。 このセクションで前述したように、Windows では、次の同期プリミティブを使用してこの実装を有効にします。

  • イベント オブジェクトは、イベントが発生したことを 1 つ以上のスレッドに通知する方法を提供します。 プロセス内の任意のスレッドでイベント オブジェクトを作成できます。 イベントのハンドルは、CreateEventイベント作成関数によって返されます。 イベント オブジェクトが作成されると、オブジェクトへのハンドルを持つスレッドは、実行を続行する前に待機できます。
  • クリティカル セクションは、実行する前に一部の共有データ セットへの排他的アクセスを必要とするコードのセクションに使用され、1 つのプロセス内のスレッドによってのみ使用されます。 クリティカル セクションは、一度に 1 つのスレッドしか通過し得るターンタイルのようなもので、次のように動作します。
    • 一度に複数のスレッドが共有データにアクセスしないように、プロセスのプライマリ スレッドはグローバルなCRITICAL_SECTIONデータ構造を割り当て、そのメンバーを初期化します。 クリティカル セクションに入ったスレッドは、EnterCriticalSection 関数を呼び出し、データ構造のメンバーを変更します。
    • クリティカル セクションを入力しようとしているスレッドは、enterCriticalSection呼び出し、CRITICAL_SECTIONデータ構造が変更されているかどうかを確認します。 その場合、別のスレッドが現在クリティカル セクションにあり、後続のスレッドがスリープ状態になります。 クリティカル セクションを離れるスレッドは、LeaveCriticalSection呼び出し、データ構造をリセットします。 スレッドがクリティカル セクションを離れると、システムはスリープ状態のスレッドの 1 つをスリープ解除し、クリティカル セクションに入ります。
  • ミューテックスはクリティカル セクションと同じ機能を実行しますが、ミューテックスは異なるプロセスで実行されているスレッドからアクセスできる点が異なります。 ミューテックス オブジェクトを所有することは、議論の中でフロアを持つことに似ています。 プロセスは、ハンドルを返す CreateMutex関数呼び出すことによってミューテックス オブジェクトを作成します。 ミューテックス オブジェクトを要求する最初のスレッドは、その所有権を取得します。 スレッドがミューテックスで終了すると、所有権は先着順で他のスレッドに渡されます。
  • セマフォは、使用可能なリソースの参照カウントを維持するために使用されます。 スレッドは、CreateSemaphore 関数を呼び出し、リソースへのポインター、初期リソース数、および最大リソース数を渡すことによって、リソースのセマフォを作成します。 この関数はハンドルを返します。 リソースを要求するスレッドは、WaitForSingleObject 関数の呼び出しでセマフォ ハンドルを渡します。 セマフォ オブジェクトはリソースをポーリングして、使用可能かどうかを判断します。 その場合、セマフォはリソース数をデクリメントし、待機中のスレッドをウェイクアップします。 カウントが 0 の場合、別のスレッドがリソースを解放するまでスレッドはスリープ状態のままになり、セマフォはカウントを 1 にインクリメントします。

アパートメント間のインターフェイスへのアクセス

スレッド モデル の選択

In-Process サーバースレッドの問題

プロセス、スレッド、およびアパートメント

Single-Threaded とマルチスレッド通信

Single-Threaded アパートメンツ