回答:
COMスレッドモデルは「アパートメント」モデルと呼ばれ、初期化されたCOMオブジェクトの実行コンテキストは、シングルスレッド(シングルスレッドアパートメント)または多数のスレッド(マルチスレッドアパートメント)のいずれかに関連付けられます。このモデルでは、COMオブジェクトは、アパートメントで初期化されると、実行時間中、そのアパートメントの一部になります。
STAモデルは、スレッドセーフでないCOMオブジェクトに使用されます。つまり、独自の同期を処理しません。これの一般的な用途は、UIコンポーネントです。したがって、別のスレッドがオブジェクトと対話する必要がある場合(フォームのボタンを押すなど)、メッセージはSTAスレッドにマーシャリングされます。Windowsフォームメッセージポンプシステムは、この例です。
COMオブジェクトが独自の同期を処理できる場合、マーシャリングされた呼び出しなしで複数のスレッドがオブジェクトと対話できるMTAモデルを使用できます。
すべては、オブジェクトへの呼び出しがどのように処理され、どれだけの保護が必要かによって決まります。COMオブジェクトは、ランタイムに複数のスレッドから同時に呼び出されないように保護するように要求できます。異なるスレッドから同時に呼び出すことはできないため、独自のデータを保護する必要があります。
さらに、呼び出しがユーザーインターフェイススレッドから行われた場合、ランタイムはCOMオブジェクト呼び出しがユーザーインターフェイスをブロックしないようにする必要もあります。
アパート、ライブへのオブジェクトのための場所である、と彼らは1つまたは複数のスレッドが含まれています。アパートは、通話が行われたときに何が起こるかを定義します。アパートメント内のオブジェクトへの呼び出しは、そのアパートメント内の任意のスレッドで受信および処理されます。ただし、すでに適切なアパートメントにあるスレッドによる呼び出しは、それ自体で処理されます(つまり、オブジェクトへの直接呼び出し)。
スレッドは、シングルスレッドアパートメント(その場合は、そのアパートメント内の唯一のスレッド)またはマルチスレッドアパートメントのいずれかにできます。スレッドがそのスレッドのCOMを初期化するときにどれを指定するか。
STAは主に、特定のスレッドに関連付けられているユーザーインターフェイスとの互換性を保つためのものです。STAは、非表示ウィンドウへのウィンドウメッセージを受信することにより、処理する呼び出しの通知を受信します。発信呼び出しを行うと、モーダルメッセージループを開始して、他のウィンドウメッセージが処理されないようにします。呼び出されるメッセージフィルターを指定して、アプリケーションが他のメッセージに応答できるようにすることができます。
対照的に、すべてのMTAスレッドは、プロセスに対して単一のMTAを共有します。使用可能なスレッドがない場合、COMは新しいワーカースレッドを開始して着信呼び出しを処理する場合があります(プール制限まで)。発信呼び出しを行うスレッドは単にブロックします。
簡単にするThreadingModel
ために、クラスのキーの値を設定することにより、DLLに実装されているオブジェクトのみを考慮します。これらのオブジェクトは、レジストリでサポートするものをアドバタイズします。4つのオプションがあります。
ThreadingModel
存在しない値)。オブジェクトはホストのメインUIスレッドで作成され、すべての呼び出しはそのスレッドにマーシャリングされます。クラスファクトリは、そのスレッドでのみ呼び出されます。Apartment
。これは、クラスが任意のシングルスレッドモードのスレッドで実行できることを示しています。それを作成するスレッドがSTAスレッドの場合、オブジェクトはそのスレッドで実行されます。それ以外の場合は、メインSTAで作成されます。メインSTAが存在しない場合は、そのSTAスレッドが作成されます。(これは、Apartmentオブジェクトを作成するMTAスレッドが、別のスレッドへのすべての呼び出しをマーシャリングすることを意味します。)クラスファクトリは、複数のSTAスレッドによって同時に呼び出すことができるため、内部データを保護する必要があります。Free
。これは、MTAで実行するように設計されたクラスを示します。STAスレッドによって作成された場合でも、常にMTAに読み込まれます。これは、STAスレッドの呼び出しがマーシャリングされることを意味します。これは、Free
オブジェクトが通常、ブロックできることを期待して書かれているためです。Both
。これらのクラスは柔軟性があり、作成元のアパートメントに読み込まれます。ただし、MTAに読み込まれている場合は同時呼び出しから内部状態を保護する必要がありますが、STAに読み込まれている場合はブロックしないでください。.NET Frameworkから、基本的には[STAThread]
、UIを作成するスレッドで使用するだけです。Apartment
マークされたCOMコンポーネントを使用する場合を除いて、ワーカースレッドはMTAを使用する必要があります。次にコンポーネント)。コンポーネントがSTAにあるかMTAにあるかに関係なく、スレッドごとに個別のCOMオブジェクトを使用する方がずっと簡単です。
私は既存の説明があまりにもわかりづらいことに気づきます。ここに私が分かりやすい英語で説明します:
STA:スレッドがSTAに設定されたCOMオブジェクトを作成する場合(CoCreateXXXを呼び出すときに、COMオブジェクトをSTAモードに設定するフラグを渡すことができます)、このスレッドのみがこのCOMオブジェクトにアクセスできます(つまり、STAは、シングルスレッドアパートメントを意味します)、このCOMオブジェクトのメソッドを呼び出そうとする他のスレッドは、COMオブジェクトを作成(所有)するスレッドにメッセージを配信するように静かに変更されています。これは、UIコントロールを作成したスレッドだけが直接それにアクセスできるという事実によく似ています。また、このメカニズムは、複雑なロック/ロック解除操作を防止するためのものです。
MTA:スレッドがMTAに設定されたCOMオブジェクトを作成する場合、ほとんどすべてのスレッドがそのメソッドを直接呼び出すことができます。
それはほとんどそれの要点です。技術的には、「STA」段落など、言及しなかった詳細がいくつかありますが、作成者スレッド自体はSTAである必要があります。しかし、これはSTA / MTA / NAを理解するために知っておくべきことのほとんどです。
STA(シングルスレッドアパートメント)は基本的に、一度に1つのスレッドのみがコードと対話するという概念です。アパートへの通話は、ウィンドウメッセージ(非表示を使用)を介してマーシャリングされます。これにより、呼び出しをキューに入れ、操作が完了するのを待つことができます。
MTA(Multi Threaded Apartment)は、多くのスレッドがすべて同時に動作できる場所であり、開発者はスレッドセキュリティを処理する責任があります。
COMのスレッドモデルについて学ぶべきことは他にもたくさんありますが、それらが何であるかを理解するのに問題がある場合は、ほとんどのCOMオブジェクトがSTAであるため、STAとは何か、およびそれがどのように機能するかを理解することが最善の出発点になると思います。
アパートメントスレッド。スレッドが、使用しているオブジェクトと同じアパートメントにある場合、アパートメントスレッドです。これはCOMの概念にすぎないと思います。それは、オブジェクトと対話するオブジェクトとスレッドについて話す方法にすぎないからです…
COMまたはOLEコントロールをホストする各EXEは、アパートメントの状態を定義します。アパートの状態はデフォルトでSTAです(ほとんどのプログラムではSTAである必要があります)。
STA-必然的にすべてのOLEコントロールはSTA内に存在する必要があります。STAは、COMオブジェクトを常にUIスレッドで操作する必要があり、(MFCのUI要素と同様に)他のスレッドに渡すことができないことを意味します。ただし、プログラムはまだ多くのスレッドを持つことができます。
MTA-プログラム内の任意のスレッドでCOMオブジェクトを操作できます。
私の理解として、「アパートメント」は、COMオブジェクトをマルチスレッドの問題から保護するために使用されます。
COMオブジェクトがスレッドセーフでない場合は、それをSTAオブジェクトとして宣言する必要があります。その後、それを作成したスレッドだけがそれにアクセスできます。作成スレッドは、それ自体をSTAスレッドとして宣言する必要があります。内部的には、スレッドはSTA(スレッドローカルストレージ)にSTA情報を格納します。この動作は、スレッドがSTAアパートメントに入るときに呼ばれます。他のスレッドがこのCOMオブジェクトにアクセスする場合、作成スレッドへのアクセスをマーシャリングする必要があります。基本的に、作成スレッドはメッセージメカニズムを使用して着信呼び出しを処理します。
COMオブジェクトがスレッドセーフの場合は、MTAオブジェクトとして宣言する必要があります。MTAオブジェクトにはマルチスレッドからアクセスできます。
COMオブジェクトdllを呼び出すコード(たとえば、プロプライエタリデータファイルを読み取るため)は、ユーザーインターフェイスでは正常に機能するかもしれませんが、サービスから不可解にハングアップします。理由は、.Net 2.0のユーザーインターフェイスではSTA(スレッドセーフ)を想定し、サービスではMTA(それ以前はサービスはSTAを想定)を想定しているためです。サービス内のCOM呼び出しごとにSTAスレッドを作成する必要があるため、オーバーヘッドが大幅に増える可能性があります。