1

WinFormとコンソールアプリケーションに関して、STAとMTAの違いを理解するのに助けが必要です。parallel.invokeを使用して、サードパーティのCOMインターフェイスを使用して関数を並列に実行しています。コンソールアプリケーションでこれを行うと、すべてが正常に機能し、コードは実際に並行して実行されます。しかし、Winformで同じことを行うと、シーケンシャルになり、winformのエントリポイントの上にあるSTAtrhreadタグを削除すると、並行して正常に動作し始めます。誰かがこの振る舞いを説明できますか?、どんな提案でもいいでしょう!

4

2 に答える 2

1

COM には、.NET にはまったくない機能があります。COM クラスは、スレッドセーフかどうかを指定できます。これは、ThreadingModel という名前のレジストリのキーを使用して行います。ほとんどの .NET クラスと同様に、COM クラスの大部分はスレッド セーフではないため、"Apartment" を指定します。これは、「自分が作成されたスレッドからのみ電話をかける」ことを意味するややあいまいな用語です。これにより、スレッドセーフが自動的に提供されます。

これを機能させるには、COM オブジェクトを作成するスレッドが、スレッド セーフではない COM クラスに対して提供するサポートの種類を示す必要があります。STA スレッドは安全なホームです。要件は、UI スレッドが行うように、スレッドがメッセージ ループをポンピングすることです。メッセージ ループは、COM がワーカー スレッドからオブジェクトを作成したスレッドへの呼び出しをマーシャリングするメカニズムです。MTA に参加するスレッドは、特にサポートを提供しないと述べています。

COM は MTA スレッドに対して何らかの処理を行う必要があります。スレッド セーフではない COM オブジェクトには適していません。新しいスレッド、つまり STA スレッドを作成して、COM オブジェクトに安全なホームを提供します。これは非常に非効率的です。すべてのメソッド呼び出しをマーシャリングする必要があります。また、オブジェクトが内部で状態を共有している場合、COM クラスは依然としてスレッドセーフではない可能性があります。

つまり、Winforms のケースで何が起こっているかというと、STA であるメイン スレッド上にすべてのオブジェクトを作成したということです。並列ワーカー スレッドから呼び出しを行うと、それらの呼び出しはすべてマーシャリングされ、シリアル化されて STA スレッドに戻されます。必然的に、それらは 1 つずつ実行され、同時実行性は得られません。

コンソールの場合、MTA スレッドでそれらを作成しました。そのため、COM はオブジェクトごとにスレッドを作成する必要があります。ワーカー スレッドでのメソッド呼び出しは引き続きマーシャリングされますが、複数のスレッドにマーシャリングされます。そのため、かなりのオーバーヘッド、余分なスレッドの束を犠牲にして、同時実行性を得ることができます。また、サーバーが内部で状態を共有する場合の障害のリスク。

ワーカー スレッドで COM オブジェクトを作成して、Winforms ケースをコンソール ケースと同じにします。非常に徹底的にテストしてください。

于 2012-07-11T21:16:31.917 に答える
0

STA と MTA はどちらも COM/ActiveX の「スレッド モデル」であり、1990 年代半ばまでさかのぼります。

ここに良いリンクがあります:

  • 駅:

プロセスには、CoInitialize を呼び出したスレッドごとに 1 つのシングルスレッド アパートメント (STA) があります。これらの各アパートメントには、0 個以上の COM オブジェクトが関連付けられている場合があります。ただし、その名前が示すように、1 つの特定のスレッド (CoInitialize を呼び出してアパートメントを作成したスレッド) のみが、アパートメント内のオブジェクトに直接アクセスできます。

  • MTA:

フリースレッド アパートメントと呼ばれることもあるマルチスレッド アパートメントは、はるかに単純なモデルですが、開発者がオブジェクトのスレッド同期を実装する必要があるため、開発はより困難です。これは明らかに重要なタスクです。良い面としては、STA の同期メカニズムを削除すると、開発者はスレッド同期の使用をより細かく制御できるようになります。アパートメント全体へのアクセスを同期する STA の非常に保守的なアプローチを採用するのではなく、実際に必要な場所に適用できます。

1 つの問題は、コンポーネントに最適なスレッド モデルを選択することです (デフォルトは STA、IIRC です)。もう 1 つの問題は、コンポーネントと別のスレッド モデルを使用するコンポーネントとの間でデータをマーシャリングする必要がある場合にランタイムが行うことです。上記のリンクでは、両方について説明しています。

于 2012-07-11T19:48:51.510 に答える