Com Marshallingは、両方のスレッドモデルを備えたオブジェクトの(これまで)ネクサリーになりますか?

StackOverflow https://stackoverflow.com/questions/19847555

質問

これはによってトリガーされます 別の質問.

具体的には、私はプロセスcomクラスを持っています、それはで定義されています CLSIDレジストリ を持っているように ThreadingModelBoth.

私たちのプロセスは、このオブジェクトを介してアクティブにします CoCreateInstance (いいえ CoCreateInstanceEx, 、それが重要な場合でも、InProc DLLサーバーにとっても重要な場合)

のスレッドモデルが与えられます Bothそして、にリストされているルールが与えられます ドキュメント:

Threading model of server | Apartment server is run in
------------------------------------------------------
Both                      | Same apartment as client

そして、ハンスが他の答えに書いていることを考えると、

...マーシャリングは、クライアントコールを別のスレッドで行う必要があるときに発生します。 ... Comclass要素で指定されたスレッドモデルがそれを要求する場合に発生する可能性があります。言い換えれば、COMオブジェクトが1つのスレッドで作成されたが、別のスレッドで呼び出され、サーバーがスレッドセーフではない場合。

私の暫定的な結論は、そのようなオブジェクトが 一度もない オブジェクトは常にクライアントと同じアパートに住んでいるため、インターフェイスへの呼び出しの暗黙のマーシャルが必要です。

クライアントプロセスが実行されていても、それは正しいですか sta?

役に立ちましたか?

解決

はい、マーシャリングがあるかもしれません。

COMクラスのクライアントがSTAで実行され、別のアパートからクラスを呼び出しようとする場合、それが作成されたアパートにマーシャルする必要があります。

com用語は本当に混乱する可能性があります。この場合、「クライアント」を参照すると、アプリケーション全体ではなく、スレッドに言及しています(暗示されるように)。

Both サーバーのスレッドモデルがクライアントに適合していることを意味します。つまり、クラスをインスタンス化すると、作成されたスレッドのスレッドモデルになります。 STAにサーバーをインスタンス化しているため、サーバーはSTAを使用します。つまり、作成したスレッドでのみ呼び出されます。別のスレッドがそれを呼び出そうとすると、それが作成されたスレッドにマーシャリングします。

他のヒント

私はこれを投稿するのを助けることはできませんが、それは質問に対する直接的な答えではありません。

Comの黄金時代からの素晴らしいMSKBの記事があります: 情報:OLEスレッドモデルの説明と仕組み. 。まだそこに、そしてすべての関連情報があります。 ポイントは、ルールに従っている場合、マーシャリングがあるかどうかを心配しないでください。. 。オブジェクトを次のように登録するだけです ThreadingModel=Both, 、フリースレッドマーシャラーを集計します CoCreateFreeThreadedMarshaler, 、そして完了します。 comは、必要に応じて可能な限り最善の方法でマーシャリングを行います。クライアントのアパートモデルに応じて、クライアントコードは、ルールにも従う場合、インターフェイスへの直接的なポインターを受信する場合があります。

インターフェイスのメソッドが呼び出されたときに受信できる「エイリアン」インターフェイスは、同じスレッドにとどまるため、コールの範囲で有効になります。 保存する必要がない場合は、それだけです。

ただし、「エイリアン」インターフェイスをキャッシュする必要がある場合、これを行う正しい方法は、それを使用して保存することです CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:

保存するには:

  • クリティカルセクションを入力します。
  • 電話 CoMarshalInterThreadInterfaceInStream と保存します IStream メンバーフィールドのポインター。
  • 重要なセクションを離れます。

それを取得するために

  • クリティカルセクションを入力します。
  • 電話 CoGetInterfaceAndReleaseStream インターフェイスを取得します
  • 電話 CoMarshalInterThreadInterfaceInStream そしてそれをもう一度保存します IStream 将来の使用のために
  • 重要なセクションを離れます。
  • 現在の呼び出しの範囲でインターフェイスを使用します

それをリリースするには:

  • あなたがそれを保持する必要がなくなったら、保存されたものをリリースするだけです IStream (重要なセクション内)。

「エイリアン」オブジェクトも自由に傾いており、同じプロセス内で物事が起こっている場合、後に直接インターフェイスポインターを扱う可能性があります CoGetInterfaceAndReleaseStream. 。ただし、仮定を立てるべきではありません。また、取引しているオブジェクトが元のオブジェクトであるか、com marshallerプロキシであるかを知る必要はありません。

これは、使用することでわずかに最適化できます CoMarshalInterface w/ MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData それ以外の CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, 、ストリームをリリースせずに、必要に応じて何度も同じインターフェイスを除外します。

スレッドローカルストレージを含む、より複雑な(おそらくより効率的な)キャッシュシナリオが可能です。しかし、私はそれが過剰になると信じています。私はタイミングをしませんでしたが、私はのオーバーヘッドだと思います CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream本当に低いです。

そうは言っても、あなたが状態を維持する必要があるなら スレッドアフィニティを必要とする可能性のあるリソースまたはオブジェクトを保存します, 、前述のcomインターフェイス以外に、あなた いけない あなたのオブジェクトをとしてマークします ThreadingModel=Both またはFTMを集計します。

はい、マーシャリングはまだ可能です。いくつかの例:

  1. オブジェクトはMTAスレッドからインスタンス化されているため、MTAアパートメントに配置され、そのポインターは任意のSTAスレッドに渡され、そのSTAスレッドはオブジェクトのメソッドを呼び出します。この場合、STAスレッドは、マーシャリングを介してオブジェクトにのみアクセスできます。

  2. オブジェクトはSTAスレッドからインスタンス化されているため、そのスレッドに属するSTAアパートに配置され、そのポインターは別のSTAスレッドまたはMTAスレッドに渡されます。どちらの場合も、これらのスレッドはマーシャリングを介してオブジェクトにのみアクセスできます。

実際、次の2つのケースでのみマーシャリングがないと期待できます。

  1. オブジェクトはMTAスレッドからインスタンス化され、MTAスレッドのみがアクセスされます。両方とも、オブジェクトと同じプロセスの他のすべてのMTAスレッドをインスタンス化したものです。
  2. オブジェクトはSTAスレッドからインスタンス化され、そのまさにそのスレッドによってのみアクセスされます

そして、他のすべての場合、マーシャルは始まります。

ThreadingModel =両方とも、COMサーバーの作成者が自分のコードがスレッドセーフであることを保証できるが、同じ保証を与えることができないことを意味します。 他の 彼が書いていないコードは、スレッドセーフの方法で呼び出されます。このような外国のコードを実行する最も一般的なケースはコールバックを使用することです。接続ポイントは最も一般的な例です(通常、クライアントのランタイムで「イベント」と呼ばれます)。

そのため、サーバーインスタンスがSTAで作成された場合、クライアントプログラマーはイベントが同じスレッドで実行されることを期待します。そのようなイベントを発射するサーバーメソッドが別のスレッドから呼び出されたとしても。そのためには、その呼び出しが整理される必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top