複数のスレッドからCOMインタフェースをCallしたときに並列に実行されるには?

[戻る]
RYO 2016/06/28(火) 16:23:46
COMクライアント上で複数のワーカースレッドを起こします。
そのワーカースレッド上で、CoInitializeEx / CoCreateInstanceをCallし、
同じCOMサーバにアクセスできるようにします。

その各々のワーカースレッド上で、COMサーバにあるインタフェース(例えばA()とする)をCall
します。
このワーカースレッド上のA()をCallする処理を、並列で実行します。

この時、COMサーバのA()は、並列で処理してほしいのですが、(ワーカースレッドで並列にア
クセスしているため)
同期で処理されてしまいます。
例えば、ワーカースレッド1のA()の処理が終わったら、ワーカースレッド2のA()の処理がは
じまる・・・
のような感じです。

CoInitializeEx時の、COINIT_APARTMENTTHREADED、COINIT_MULTITHREADEDは両者とも試しまし
たが、
並列処理されているようには見えませんでした。


どのように実装したら並列に処理できますでしょうか?
どなたかご教授をお願いいたします。

aetos 2016/06/28(火) 16:46:46
レジストリの CLSID の下にある ThreadingModel が Apartment になってませんでしょう
か。

RYO 2016/06/29(水) 08:25:41
aetosさま、ご回答ありがとうございます。
確認したところ「Both」になっています。問題ないですよね?

RYO 2016/06/29(水) 11:40:05
追加の情報になります。

COMクライアントの方は、別々のThread IDからA()をコールしているのですが、
COMサーバの方は、1つのThreadでA()を処理しているように見えます。。

ITO 2016/06/30(木) 09:21:37
> そのワーカースレッド上で、CoInitializeEx / CoCreateInstanceをCallし、
> 同じCOMサーバにアクセスできるようにします。
ここまずくないですか?
 普通、初期化、終了処理は一回限り、データ取得等の処理をスレッドで行うのが
普通ですが、COMは違いましたっけ?

仲澤@失業者 2016/06/30(木) 10:37:48
COMはMSXMLぐらいしか使わないので詳しくありませんが、

https://msdn.microsoft.com/ja-jp/library/windows/desktop/ff485844(v=vs.85).aspx

では、CoInitializeEx()はスレッド毎に実行する必要があると明記されています。
ただし、そこには

1.当該のCOMのポインタをスレッド間で共用しない場合。
 つまりCOMのポインタはそのスレッド専用で他のスレッドにポインタを渡さない場合。
   又は
2.そのスレッドがメッセージループを持っている

1.2.のいずれかが当てはまる場合は、「アパートメントスレッド」でCoInitializeEx()す
るようにとあります。

1.も2.も当てはまらない場合は「マルチスレッド」でCoInitializeEx()するらしいですよ
。

仲澤@失業者 2016/06/30(木) 10:47:25
間違った。orz.

1.2.のどちらかが、当てはまらない場合は「マルチスレッド」で、

上記以外は「アパートメントスレッド」ですね。

すみません。

ITO 2016/06/30(木) 14:52:42
>CoInitializeEx()はスレッド毎に実行する必要があると明記されています。

なるほど、COMはシングルスレッドしかやってないです。
スレッド毎となると、スレットは個々にハンドルを持たないといけなくなりますね。
個数を制限し、かつハンドルを把握しておかないとリソースが足りなくなる
かも知れませんね。

 

aetos 2016/06/30(木) 15:41:14
> 確認したところ「Both」になっています。問題ないですよね?

その設定自体は問題なさそうですね。

レジストリの ThreadingModel が Both の場合、CoCreateInstance を呼んだスレッドのス
レッディングモデルが使用されます。
CoCreateInstance で作成した COM サーバーは、CoCreateInstance したスレッドが COINI
T_MULTITHREADED で初期化されていれば MTA、COINIT_APARTMENTTHREADED で初期化されて
いれば STA に属します。
COM サーバーが STA に属していると、他のスレッドからの処理要求はメッセージ ループ
によって直列化されるので並列処理になりません。

確認すべき点はこんな感じでしょうか。
1. ワーカースレッドで CoInitializeEx を COINIT_MULTITHREADED で呼んでいること
2. CoInitializeEx が成功していること
3. GetCurrentThreadId 等でスレッド ID を取得してみる

aetos 2016/06/30(木) 15:42:54
あぁ、あとはもちろん
4. COM サーバーのメソッド A() の中で排他制御を行っていないこと
も。
もちろん必要な排他制御はすべきですが、並列処理を企図する以上最小限でなければなり
ませんからね。

古いスレッドには追加発言できません。