ここには複数の質問があります。
TL;DR:
ニュートラル オブジェクト:
- STA および MTA オブジェクトよりも処理中のマーシャリングが少し少なくなります。
- スレッドの切り替えを避ける
- インターフェイス ポインタは自動的にマーシャリングされます
- ニュートラル アパートメントは、ニュートラル オブジェクトが生きている限り存続します。
- COM ユーティリティ関数を使用して待機するか、スレッドの種類に応じて使用する Win32 待機関数を選択して、あらゆる種類のスレッドで実行する準備ができている必要があります。
フリー スレッド オブジェクト:
- インプロセスマーシャリングが実質的に発生しない
- スレッドの切り替えを避ける
- インターフェイス ポインターは自動的にマーシャリングされません。
- ライフタイムはアクティベーション アパートメントに関連付けられています
- COM ユーティリティ関数を使用して待機するか、スレッドの種類に応じて使用する Win32 待機関数を選択して、あらゆる種類のスレッドで実行する準備ができている必要があります。
FreeThreadedDOMDocument、ニュートラル アパートメント、およびフリースレッド マーシャラーの間に何らかの関連はありますか?
TL;DR:FreeThreadedDOMDocument
のスレッド モデルは「Both」なので、アクティブ化 (作成) されたアパートメントに関連付けられます。これはフリー スレッド マーシャラーを集約するため、フリー スレッド オブジェクトです。
は、オブジェクトがフリー スレッド マーシャラーFreeThreadedDOMDocument
を集約する COM クラスです。 このマーシャラーが行うことは、インプロセスでマーシャリングするたびに生のポインターを提供することです (つまり、set to .IMarshal::MarshalInterface
dwDestContext
MSHCTX_INPROC
フリー スレッド マーシャラーを集約するオブジェクトとして、フリー スレッド オブジェクトの定義を使用します。
Windows 2000 より前では、フリー スレッド オブジェクトのスレッド モデルは「ニュートラル」または「両方」として指定する必要があります。これにより、任意のスレッドで作成および使用でき、コンテキスト スイッチを回避できます。
スレッド モデルが "Both" として指定されている場合、オブジェクトの有効期間は、オブジェクトが作成されたアパートメントに関連付けられます。たとえば、STA スレッドが終了すると、そのアパートメント内で作成されたすべての空きスレッド オブジェクトは破棄されるか、無効になります。
私の知る限り、ニュートラル アパートメント オブジェクトはフリースレッド マーシャラーでサポートされています。
いいえ、ニュートラル オブジェクトへのプロキシは、COM コンテキストをセットアップするだけなので、他のインプロセスプロキシよりも少し軽量ですが、完全なマーシャリングが発生することはなく、スレッドの切り替えが回避されます。
FreeThreadedDOMDocument はフリー スレッド マーシャラーを使用しておらず、フリー スレッドとして少し紛らわしいと呼ばれているということですか?
いいえ、FreeThreadedDOMDocument
フリー スレッド マーシャラーを使用します。
歴史的には、 Microsoft が独自のサポートを提供する前に、フリーのスレッド化されたオブジェクトが既に存在し (人気のため、おそらく、フリーのスレッド化されたマーシャラーのほとんどが不安定だったため)、ニュートラル アパートメントは Windows 2000 でのみ登場しました。
そのため、 のインスタンスはFreeThreadedDOMDocument
フリー スレッド マーシャラーを集約するためフリー スレッドであり、各インスタンスの有効期間はそれが作成されたアパートメントに関連付けられています。通常、影響はほとんどありませんが、STA スレッドのスレッドプールなどでは、所有スレッドが (正常に、またはリソースを再利用するために) 終了して作成されると、STA が出入りするため、影響がより頻繁に観察されます。たとえば、クラシック ASP はデフォルトで STA スレッドを使用します。
PS:別の回答で次の件名に言及しましたが、質問も異なるため、内容が少し異なると思います。
現在のスレッド モデルの値は次のとおりです。
- なし: メイン STA を使用
- "Apartment": 任意の STA を使用します。つまり、現在のアパートメントが STA または NA over STA の場合は現在の STA を使用し、それ以外の場合はホストSTA を使用します (これについては後で詳しく説明します)。
- 「無料」: MTA を使用
- 「両方」:現在のアパートを使用
- 「ニュートラル」: NA を使用
存在しないアパートメントについては、COM が必要に応じて作成します。
ここにはいくつかの特徴があります。
- メイン STA を使用するには、「メイン」などのより賢明なものの代わりに、スレッド モデルについて言及してはなりません。
- 「ニュートラル」以外のすべての名前は、今日では意味がありません。
- 「アパート」は今のアパートのような感じですが、そうではありません
- 「フリー」はフリー スレッド オブジェクトのように感じますが、そうではありません
- 「Both」と聞くと2種類しかないと思われがちですが、STA、MTA、NAの3タイプあります。
メイン STA は、最初に作成された STA です。スレッド モデルが指定されていないクラスでのみ問題になります。
複数の STA が存在する可能性がありますが、最大で 1 つの MTA と 1 つの NA があります。
アクティブな MTA が存在する場合、COM 用に初期化されていないスレッドは、呼び出されない場合は暗黙的に MTA に含まれますCoInitializeEx(NULL, COINIT_MULTITHREADED)
が、MTA の有効期間にはまったく影響しません。つまり、スレッドが MTA を使用している間に MTA が破棄される可能性があります。 . これはほとんど文書化されておらず、ほとんど信頼できないため、これに頼るべきではありません。
暗黙的に作成されたアパートメントは、ホスト STA およびホスト MTA と呼ばれます。あなたはそれらを制御することはできません(CoUninitialize
そのアパートにいる間に不正行為をしない限り;注:実際にこれをしないでください)。実際、STA の外部または STA で実行されている NA の外部で「アパートメント」オブジェクトをアクティブ化すると、ホスト STA でアクティブ化されます。ホスト STA が最初に初期化された STA であった場合、これがメイン STA になる可能性もあります。
ホスト アパートメントをサポートするすべての COM スレッドはバックグラウンド スレッドであるため、アプリケーションの終了を妨げません。
ニュートラル オブジェクトをアクティブ化するときに NA を作成する以外に、NA を制御することはできません。直接入力することはできませんが、ニュートラル アパートメントのコンテキストでコールバックを実行するメソッドを使用して、独自の中立オブジェクトを作成できます。このコールバックは、フリー スレッド オブジェクトである可能性があります。
Free、Both、または Neutral としてマークされた COM クラス間の実装の違いは何ですか?
"Free" として宣言されたアパートメントを持つ COM クラスは、MTA に属するオブジェクトになります。このようなオブジェクトは、それらが実行されるスレッドがウィンドウ メッセージをポンピングする必要がないと想定する場合があります。基本的に、彼らはブロックするかもしれません。
フリー スレッド オブジェクトとニュートラル オブジェクトは、任意のアパートメントの下で実行できるように準備する必要があります。フリー スレッド オブジェクトの場合、その理由は明らかです。コンテキスト マーシャリングをバイパスするため、メソッドは任意のスレッドで実行されます。ニュートラル オブジェクトの場合、どの種類のアパートメントが( を通じてCoGetApartmentType
) アクティブであったかが区別されます。
いずれの場合も、COM のユーティリティ関数を使用する必要がありますCoWaitForMultipleHandles
。たとえば、ブロックされて STA では受け入れられない や、ウィンドウ メッセージ キューにアクセスしておそらく暗黙的に作成され、通常は MTA では受け入れられない などです。WaitForMultipleHandles
[
Ex
]
MsgWaitForMultipleHandles
[
Ex
]
アパートメント タイプを自分で確認し、適切な Win32 待機関数を使用するか、STA でタイムアウト付きのメッセージを待機およびポンプするポーリング戦略を使用するかを選択できます。これは、ハンドル以外のものを待機している場合や、特定の待機ロジック。
フリー スレッド オブジェクトとニュートラル オブジェクトの最も顕著な違いは、他の COM オブジェクトのマーシャリングです。
ニュートラル オブジェクトを使用している間、着信および発信インターフェイス ポインターは自動的にマーシャリングされます。たとえば、着信インターフェイス ポインターをフィールドに格納できます。
フリー スレッド オブジェクトを使用している間、着信および発信インターフェイス ポインターはまったくマーシャリングされません。つまり、同じアパートメント内のオブジェクトへの生のポインターを取得するか、他のアパートメント内のオブジェクトへのプロキシを取得します。これらのプロキシは、現在のアパートにも関連付けられています。
たとえば、着信生ポインタは、現在のアパートメントに属するオブジェクトを取得していることを意味するため、オブジェクトへの参照を保存する場合は、それをマーシャリングする必要があります。
着信プロキシは、別のアパートメント内のオブジェクトへのプロキシを取得していることを意味しますが、このプロキシは現在のアパートメントに関連付けられています。このプロキシも保存できません。具体的には、標準プロキシ/スタブのアパートメント検証にもかかわらず、STA プロキシはスレッド アフィニティを持つ場合があります。それもマーシャリングする必要があります。しかし心配はいりません。プロキシをマーシャリングしてもスタック マーシャリングは行われません。再度非整列化すると、プロキシへのプロキシではなく、オブジェクトへのプロキシが取得されます。
フリー スレッド オブジェクトがインターフェイス ポインターを格納する必要がある場合は、常に手動でマーシャリングする必要があります。また、このインターフェイス ポインターからメソッドを呼び出す必要がある場合は、手動でアンマーシャリングする必要があります。
通常、グローバル インターフェース テーブル(GIT; 別の誤解を招く名前、実際にはインプロセステーブル) がこの目的に使用されます。
私が理解している限り、それらはすべてスレッドセーフでなければなりませんが、なぜ違いがあるのでしょうか?
スレッドセーフに関しては、違いはありません。
しかし、前の質問で説明したように、インターフェイス ポインターを格納する際には大きな違いがあり、オブジェクトのアクティブ化と有効期間に関しては微妙な違いがあります。
ニュートラルがフリースレッドのマーシャラーをサポートするというのは正しいですか?
フリー スレッド マーシャラーは実質的にアパートメントを無視するため、正しく動作、同期、またはロックするのはメソッドの責任です。したがって、どちらのアパートメントもフリー スレッド マーシャラーをサポートする必要はありません。すべてのアパートメントをサポートする必要があるのは、フリー スレッド オブジェクトです。
「ニュートラル」を含む任意のスレッド モデルを使用して、フリー スレッド マーシャラーをオブジェクトに集約することができます。
ニュートラル アパートメント マーシャラーによるコンテキストのセットアップがボトルネックであることがわかった場合は、格納されたインターフェイス ポインターを手動でマーシャリングする代わりに、フリー スレッド マーシャラーの使用を検討してください。そうでない場合は、ニュートラル アパートメントを使用してください。