STA でのマーシャリング
STA(Single Thread Apartment)のスレッディングモデルで COM を生成して、何らかの処理を COM に投げた場合、その処理は即座に実行されるわけではなく、マーシャラーによってメッセージキューに溜められ、そのメッセージが処理されるのを待ちます。
普段はそんなことあまり意識する必要が無いのだけれども、コネクションポイントを張っている場合は注意が必要です。
何でかというと、COM 側から Sink 側へ投げる処理も、その処理を Sink 側のメッセージキューに溜めて、そのメッセージが処理されるのを待つので、
- COM 側が Sink 側を呼び出す。
- この要求は Sink 側のメッセージキューに溜められ、COM はその処理が完了するのを待つ。
- Sink 側が COM 側のメソッドを呼び出す。
- この要求は COM 側のメッセージキューに溜められ、Sink 側はその処理が完了するのを待つ。
- どう見てもデッドロックです。本当に(ry
てなことになります。
問題としては、Sink 側が COM に呼ばれてすぐに COM のメソッドを呼び出していることにあるので、この部分を ::PostMessage() とかして、自分のメッセージキューに溜めて遅延処理を行えばいいのですが、そういった負担を強いる COM はどうかと思います。
なので、COM が Sink を呼び出す際にスレッドを生成してやり、スレッド内で Sink 側のメソッドを呼び出します。
で、メインスレッドはその処理が終わるのを待ちながら、メッセージの処理も同時に行います。
こうすることで、Sink 側の処理を行っている途中にメッセージキューに要求が溜まっても正常に処理することが可能です。
でもスレッド作るのやだなぁ……(;´Д`)
追記:
よく考えてみれば、COM から Sink を呼び出す際にメッセージキューに溜めている場合、その時点でデッドロックになる可能性もあるけれど、そんな状態になったことないような気が……。
ということは、COM から Sink を呼び出す際にはメッセージキューとは別の機構を使ってる?
追記2:
STA の場合は別スレッドから Sink を呼び出すというのが出来ないっぽい?
だとすれば MTA にするしか無いのかなぁ……(;´Д`)