回答:
COMは.NETの祖父です。それらにはかなり高い目標がありました。COMが行うことの1つは、.NETが完全にスキップすることの1つは、クラスのスレッド化の保証を提供することです。COMクラスは、それが持つスレッド化要件の種類を公開できます。また、COMインフラストラクチャにより、これらの要件が確実に満たされます。
これは.NETには完全にありません。たとえば、複数のスレッドでQueue <>オブジェクトを使用できますが、適切にロックしないと、コードに厄介なバグがあり、診断が非常に困難になります。
COMスレッドの正確な詳細が大きすぎて、投稿に収まりません。質問の詳細に焦点を当てます。COMオブジェクトを作成するスレッドは、スレッドオプションが制限されているCOMクラスにどのようなサポートを提供するかをCOMに通知する必要があります。これらのクラスの大部分は、いわゆるApartmentスレッドのみをサポートしており、それらのインターフェースメソッドは、インスタンスを作成したスレッドからのみ安全に呼び出すことができます。つまり、「スレッディングはまったくサポートしていません。間違ったスレッドから呼び出さないように注意してください」と発表しています。クライアントコードは、実際にあってもない別のスレッドからそれを呼び出します。
STA(シングルスレッドアパートメント)とMTAの2種類があります。これは、CoInitializeEx()呼び出しで指定されます。この関数は、COMで何かを実行するスレッドによって呼び出される必要があります。CLRは、スレッドを開始するたびにその呼び出しを自動的に行います。プログラムのメインスタートアップスレッドの場合、Main()メソッドの[STAThread]または[MTAThread]属性から渡す値を取得します。デフォルトはMTAです。自分で作成したスレッドの場合は、SetApartmentState()の呼び出しによって決定されます。デフォルトはMTAです。スレッドプールスレッドは常にMTAであり、変更できません。
Windowsには、STAを必要とする多くのコードがあります。自分で使用する注目すべき例は、クリップボード、ドラッグ+ドロップ、シェルダイアログ(OpenFileDialogなど)です。また、UIオートメーションプログラムやメッセージを監視するためのフックなど、目に見えない多くのコード。そのコードはどれもスレッドセーフである必要はありません。その作成者は、どのプログラムで使用されるかを知らずに安全にすることは非常に困難です。したがって、ウィンドウを作成するスレッドと同様に、WPFまたはWindowsフォームプロジェクトのUIスレッドは、そのようなコードをサポートするために常にSTAである必要があります。
COMに対してスレッドがSTAであるという約束は、シングルスレッドアパートメント契約に従う必要があります。彼らはかなり硬いですし、契約を破るとトラブルを診断するのが難しくなります。要件は、スレッドを一定時間ブロックしないこと、およびメッセージループをポンピングすることです。後者の要件は、WPFまたはWinformsのUIスレッドによって満たされますが、独自のSTAスレッドを作成する場合は、自分で処理する必要があります。契約違反の一般的な診断はデッドロックです。
これらの要件をサポートするために、CLRにはかなりのサポートが組み込まれており、トラブルを回避するのに役立ちます。ロックステートメントとWAITONE()メソッドは、ときに、ブロックSTAスレッドにメッセージループをポンプ。ただし、これはブロックしないという要件のみを処理するため、独自のメッセージループを作成する必要があります。WPFとWinformsの両方でのApplication.Run()。
私は以前に、COMを幸せに保つためにメッセージループを持つことの重要性に関する詳細を含む回答を提供しました。ここに投稿があります。