STA と MTA についてご自身の言葉で説明していただけますか?
また、アパートメント スレッドとは何ですか。それは COM のみに関連するものですか? もしそうなら、なぜですか?
STA と MTA についてご自身の言葉で説明していただけますか?
また、アパートメント スレッドとは何ですか。それは COM のみに関連するものですか? もしそうなら、なぜですか?
COM スレッド モデルは「アパートメント」モデルと呼ばれ、初期化された COM オブジェクトの実行コンテキストが単一のスレッド (シングル スレッド アパートメント) または多数のスレッド (マルチ スレッド アパートメント) に関連付けられます。このモデルでは、COM オブジェクトは、アパートメント内で初期化されると、ランタイムの間、そのアパートメントの一部になります。
STA モデルは、スレッド セーフではない COM オブジェクトに使用されます。つまり、それらは独自の同期を処理しません。これの一般的な用途は、UI コンポーネントです。そのため、別のスレッドがオブジェクトと対話する必要がある場合 (フォームのボタンを押すなど)、メッセージは STA スレッドにマーシャリングされます。Windows フォーム メッセージ ポンピング システムは、この例です。
COM オブジェクトが独自の同期を処理できる場合は、複数のスレッドがマーシャリングされた呼び出しなしでオブジェクトと対話できる MTA モデルを使用できます。
すべては、オブジェクトへの呼び出しがどのように処理されるか、および必要な保護の程度にかかっています。COM オブジェクトは、同時に複数のスレッドから呼び出されないようにランタイムに要求できます。そうでないものは、異なるスレッドから同時に呼び出される可能性があるため、独自のデータを保護する必要があります。
さらに、COM オブジェクトの呼び出しがユーザー インターフェイス スレッドから行われた場合に、COM オブジェクト呼び出しがユーザー インターフェイスをブロックしないようにすることもランタイムで必要です。
アパートメントはオブジェクトが存在する場所であり、1 つ以上のスレッドが含まれています。アパートメントは、呼び出しが行われたときに何が起こるかを定義します。アパートメント内のオブジェクトへの呼び出しは、そのアパートメント内の任意のスレッドで受信および処理されます。ただし、適切なアパートメント内に既にあるスレッドによる呼び出しは、それ自体で処理されます (つまり、オブジェクトへの直接呼び出し)。
スレッドは、シングルスレッド アパートメント (この場合、そのアパートメント内の唯一のスレッド) またはマルチスレッド アパートメントのいずれかになります。スレッドがそのスレッドの COM を初期化するタイミングを指定します。
STA は主に、特定のスレッドに関連付けられているユーザー インターフェイスとの互換性を確保するためのものです。STA は、非表示のウィンドウへのウィンドウ メッセージを受信することによって、処理する呼び出しの通知を受け取ります。発信呼び出しを行うと、モーダル メッセージ ループを開始して、他のウィンドウ メッセージが処理されないようにします。アプリケーションが他のメッセージに応答できるように、呼び出すメッセージ フィルタを指定できます。
対照的に、すべての MTA スレッドは、プロセスに対して 1 つの 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
-marked COM コンポーネントを使用する場合を除き、MTA を使用する必要があります。その場合、STA を使用して、同じコンポーネントが複数のスレッドから呼び出された場合のマーシャリング オーバーヘッドとスケーラビリティの問題を回避します (各スレッドが待機する必要があるため)。順番にコンポーネント)。コンポーネントが STA にあるか MTA にあるかに関係なく、スレッドごとに個別の COM オブジェクトを使用すると、全体的にはるかに簡単になります。
私は既存の説明がゴツすぎると思います。わかりやすい英語での説明は次のとおりです。
STA: スレッドが STA に設定された COM オブジェクトを作成する場合 (CoCreateXXX を呼び出すときに、COM オブジェクトを STA モードに設定するフラグを渡すことができます)、このスレッドのみがこの COM オブジェクトにアクセスできます (これが STA の意味です - シングル スレッド アパートメント)、この COM オブジェクトでメソッドを呼び出そうとする他のスレッドは、COM オブジェクトを作成 (所有) するスレッドにメッセージを配信するように静かに変換されます。これは、UI コントロールを作成したスレッドだけがそれに直接アクセスできるという事実とよく似ています。このメカニズムは、複雑なロック/ロック解除操作を防ぐためのものです。
MTA: スレッドが MTA に設定された COM オブジェクトを作成すると、ほぼすべてのスレッドがそのオブジェクトのメソッドを直接呼び出すことができます。
それはほとんどそれの要点です。技術的には、「STA」の段落など、言及しなかった詳細がいくつかありますが、作成者スレッド自体が STA でなければなりません。しかし、STA/MTA/NA を理解するために知っておく必要があるのは、これだけです。
STA (Single Threaded Apartment) は基本的に、一度に 1 つのスレッドのみがコードと対話するという概念です。あなたのアパートへの呼び出しは、Windows メッセージ (非表示のウィンドウを使用) を介してマーシャリングされます。これにより、通話をキューに入れ、操作が完了するのを待つことができます。
MTA (Multi Threaded Apartment) は、多くのスレッドがすべて同時に動作できる場所であり、開発者はスレッド セキュリティを処理する責任があります。
COM のスレッド モデルについて学ぶべきことはまだたくさんありますが、それらが何であるかを理解するのに苦労している場合は、ほとんどの COM オブジェクトが STA であるため、STA とは何か、それがどのように機能するかを理解することが最良の出発点になると思います。
アパートメント スレッド。スレッドが使用しているオブジェクトと同じアパートメントに存在する場合、それはアパートメント スレッドです。これは COM の概念にすぎないと思います。なぜなら、これはオブジェクトとそれらがやり取りするスレッドについて話す方法に過ぎないからです…</p>
COM または OLE コントロールをホストする各 EXE は、そのアパートメント状態を定義します。アパートメント状態はデフォルトで STA です (ほとんどのプログラムでは STA のはずです)。
STA - 必要に応じて、すべての OLE コントロールは STA に存在する必要があります。STA は、COM オブジェクトを常に UI スレッドで操作する必要があり、他のスレッドに渡すことができないことを意味します (MFC の UI 要素と同様)。ただし、プログラムには多くのスレッドを含めることができます。
MTA - プログラム内の任意のスレッドで COM オブジェクトを操作できます。
私の理解では、「アパートメント」は COM オブジェクトをマルチスレッドの問題から保護するために使用されます。
COM オブジェクトがスレッド セーフでない場合は、それを STA オブジェクトとして宣言する必要があります。その後、それを作成したスレッドのみがアクセスできます。作成スレッドは、自身を STA スレッドとして宣言する必要があります。内部では、スレッドは STA 情報を TLS (スレッド ローカル ストレージ) に格納します。スレッドが STA アパートメントに入ることを、この動作と呼びます。他のスレッドがこの COM オブジェクトにアクセスする場合、作成スレッドへのアクセスをマーシャリングする必要があります。基本的に、作成スレッドはメッセージ メカニズムを使用してインバウンド コールを処理します。
COM オブジェクトがスレッド セーフである場合は、それを MTA オブジェクトとして宣言する必要があります。MTA オブジェクトは、マルチスレッドからアクセスできます。
補足: PowerShell 2.0 スナップインを使用している場合、それらを使用するには、-MTA オプションを指定して PowerShell バージョン 3 以降を起動する必要があります。PowerShell 2 アパートメント モデルは MTA ですが、それ以降のバージョンでは STA が既定で使用されます。他のポイントはビットです。アパートメント内の通常の呼び出しはマーシャリング (直接呼び出し) されないため、呼び出し元が x64 の場合、呼び出し先も x64 である必要があります。これを回避する唯一の方法は、リモート プロシージャ コール (RPC) を使用することです。これにより、大量のオーバーヘッドが追加されます (新しい 32 ビット プロセスを生成して、スナップイン DLL をロードし、何らかの方法で結果をクエリします)。開発者向け: 常にタイプ ライブラリを公開する - COM オブジェクトの検出と使用がはるかに簡単になります。すべてのインターフェイスは公開され、一意である必要があります。実装は、独自のものでもオープン ソースでもかまいません。
別の状況
例:
IStorage_vtbl** reference; // you got it by some means of factory
public unsafe int OpenStorage(char* pwcsName, IStorage pstgPriority, uint grfMode, char** snbExclude, uint reserved, IStorage* ppstg)
{
IStorage_vtbl** @this = (IStorage_vtbl**)reference;
IStorage_vtbl* vtbl = *@this;
if (vtbl == null)
throw new InvalidComObjectException();
Delegate genericDelegate = Marshal.GetDelegateForFunctionPointer(vtbl->method_6, typeof(delegate_6));
delegate_6 method = (delegate_6)genericDelegate;
return method(@this, pwcsName, pstgPriority, grfMode, snbExclude, reserved, ppstg);
}
このコードの断片は、COM サブシステムへの実際の呼び出しのために、インスタンスの 'this' ポインタを追加するだけです。では、この呼び出しは、IStorage STA または MTA のインスタンスを開くためのものですか?