- - PR -
アンマネージドとマネージドのスレッド対応
投稿者 | 投稿内容 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-06-27 13:41
ん、どれが? 名前つき Mutex 作る時の名前って、スレッドIDとかから生成してるんでしたっけ? それならずっこける可能性は大有り。
この辺はやや意味不明。 呼び出し先の方で意図的にメッセージポンプを回さない限り、最上位の呼び出しは保存されていると思いますよ。 | ||||||||||||||||||||
|
投稿日時: 2007-06-27 15:23
私にはなちゃさんの言うreentrantの意味がよく通じてませんが、 (reentrantって状態の話ではなくコードの書き方、質の問題では?) どっかでメッセージポンプに処理が移ってるということですか。 STAってブロックされると「暗黙のうちに」 メッセージループまわすんでしょうか? http://msdn2.microsoft.com/ja-jp/library/54z06b18(VS.80).aspx この辺の話かな? 今回の件では同じスレッドで再入しているのは確実なようなので reentrantなコードに変更すればOKなんでしょう。 mutexでDLL呼び出しを保護するんではなく、 すでに再入かどうかのフラグを保護するのがいいのかな。 STAならmutexも要りませんが。 >名前つき Mutex 作る時の名前って、スレッドIDとかから生成してるんでしたっけ? >それならずっこける可能性は大有り。 マネージなMutexもアンマネージなMutexもスレッドID使ってないと思いますよ。 マネージMutexとアンマネージMutexで同期とれますから。 | ||||||||||||||||||||
|
投稿日時: 2007-06-27 17:39
いやいや、内部実装ではなくて「このアプリケーションで」の話です。 名前つきミーテックスを作るコード片が示されていたような気がするんですが、その時に指定している名前にスレッドIDが含まれてたっけか?というお話です。 | ||||||||||||||||||||
|
投稿日時: 2007-06-27 17:54
れいさん、なちゃさん、渋木さん、お返事ありがとうございます。
自分のレベルが低くてみなさんのお話についていけないところもあるのですが(ホント、お恥ずかしいです・・・) 自分なりに確認したところまでお話しすると VB.NETのAPでコールしているOCXのメソッドの中身を替えて ・DLLのメソッドをコールしてる ↓から ・MessageBoxを表示するだけ に変更しました。 ちなみOCXのこのメソッドでは排他は行っていません。 このOCXのメソッドをVB.NETのAPで今までと同様にマルチスレッドでコールしても MessegeBoxは一つづつしか表示されませんでした。(スレッドIDは同じ値) これはOCXがSTAだからということに起因するのかと思います。 更にこのOCXのメソッドを ・MessageBoxを表示するだけ ↓から ・@MessageBoxを表示する ADLLのメソッドをコールする(このDLLのメソッドは最終的にATLのメソッドをコールしています) に変更しました。 このOCXのメソッドをVB.NETのAPでマルチスレッドでコールすると 最初はMessegeBoxは一つづつの表示でしたが、途中で二つ同時に表示されました。(スレッドIDは同じ値) またダミーのDLL(排他やALTを呼ぶとかはしていません)を作って、 このダミーDLLのメソッドをALTを呼ぶDLLのメソッドの替わりにコールするようにしてみましたが、 この場合だと最初の例と同じようにMessageBoxは一つづつしか表示されませんでした。 このことから
と関連するのかなとも考えています。 なんとなくですが、やっぱりOCXやDLLではどうしようもなくて ALT側で排他のような処理を考えてやらなきゃいけないのかと思っています・・・ | ||||||||||||||||||||
|
投稿日時: 2007-06-27 18:59
モーダルダイアログは独自にメッセージポンプを回してしまうので、OCX が元々使っているメソッド呼び出しのシリアライズに悪影響を及ぼすかもしれません。 メッセージボックスではなく、デバッグ出力に変えて検証するべきと思います。
「OCX が STA」なのではありません。 「(通常)OCX はシングルアパートメントでしか動作できないので、OCX を扱うスレッドは STA 属性で COM ランタイムを初期化しなければならない」のです。 ちょっと気になったところがあるんですが、
「OCX のメソッドをマルチスレッドでコール」しているとありますが、これ、どうやってます? OCX のメソッドは、その OCX のインスタンスを作成したスレッド以外から直接呼んではならないし、無理くり呼び出してもクラッシュすることが多いはずなんですが。 OCX のメソッドを別スレッドから呼び出すには、(COM の)マーシャリングを行わなければなりません。
であるとしても、現時点では ATL というライブラリに問題がある可能性よりは、作成物の設計や作りこみに何か潜在的な問題があったと考えるほうが妥当なんじゃないでしょうか。 # ATL がまったくのバグフリーかというと、決してそんなことはありませんが。 [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2007-06-27 19:33 ] | ||||||||||||||||||||
|
投稿日時: 2007-06-28 04:09
OCXの呼び出し側はVB.NETで作成したマネージドなアプリケーションと言う話ですので、 RCWが勝手に(COM の)マーシャリングを行うので、この場合は大丈夫かと。 で、先になちゃさんが言われてますが、RPCによる再入(re-entrant)の可能性が一番高いと思います。 DLLからサービスを呼び出すところでRPC呼び出しが発生しているため、ここで再入していると思われます。 | ||||||||||||||||||||
|
投稿日時: 2007-06-28 08:08
なるほど、確かに RCW の解説に
とありますね。 # .NET ではスレッド跨ぎの呼び出しを避けてたので知らなかった (^^; | ||||||||||||||||||||
|
投稿日時: 2007-06-28 13:42
私の考えを整理すると・・・
・ロックが効かない問題 OCXは通常STAで動作するためOCXのメソッドを呼び出す場合、 必ずOCXを作成したスレッド上で動作する。同一スレッド上で動作するため、 名前無しMutexまたは名前が同じMutexではロックできない。 # ただし、正しくマーシャリングされていればの話 # VB.NETは正しくマーシャリングする ・再入(re-entrant)している問題 OCXを作成したスレッド(めんどくさいので以下STAスレッドと呼ぶ)以外から OCXのメソッドを呼び出した場合、呼び出し元のスレッドはブロックされ、 呼び出しがSTAスレッドの実行キューに溜まる。 メッセージループが動いているなら、上記のSTAスレッドの実行キューから 処理が1つ取り出され実行が開始される。 この処理は OCX ⇒ DLL =(RPC)⇒ サービス というようにRPC経由で サービスのメソッドを実行する。DLLからサービスの呼び出し(RPC呼び出し)が完了すると RPCランタイムは戻り値等の情報をSTAスレッドの実行キューに溜める。 DLLからサービスの呼び出しが完了した後すぐにDLL側の処理に復帰してくれればいいのだが、 実際には、RPCランタイムはSTAスレッドの実行キューに先に溜まっている処理を実行する。 ここで先に溜まっている処理とは、最初に書いたSTAスレッド以外からのOCXのメソッドの呼び出しであり これが再入の原因となる。 # 実際のところマルチスレッドなので再入とは言えないか。 # マルチプロセスでマルチスレッドなCOMのシステムを構築すると # 上記のような現象には頻繁に遭遇するので、 # 典型的なCOMスレッド地獄と言えなくもないですなぁ。 |