4

スレッドAがスレッドBが作成されているとき、スレッドAがスレッドBが終了するまでWaitForSingleObjectを使用して待機しています。スレッドハンドルを持つWaitForSingleObjectがregsvr32.exeを実行している間にスタックする

問題は、スレッドBがスレッドの「thread_func」から戻っても、スレッドA が通知されないことです。

thread_func(スレッドBのメイン関数)の最後にトレース(OutputDebugString)を追加したので、スレッドBが実行を終了してもスレッドAがWaitForSingleObjectから抜けることはありません。

ここで、このコードはCOMオブジェクトにあり、上記のシナリオはregsvr32.exeを呼び出すと起きていると付け加えなければなりません(スタックされてしまいます!)ので、スレッドAはDLLMain。

スレッドAが通知されない理由は何ですか?!?!

答えて

14

ローダーロックで問題が発生する可能性があります。 Windowsでは、DLLがロード/アンロードされるたびに、またはスレッドが開始/停止されるたびにロックされる内部クリティカルセクションがあります(DllMainは常にそのロック内で呼び出されます)。待機中のスレッドAにクリティカルセクションがロックされている(つまり、DllMainのどこかで待機している)場合、別のスレッドBがシャットダウンを試みて、そのローダクリティカルセクションを取得しようとすると、デッドロックが発生します。

デッドロックの発生場所を確認するには、VS IDEデバッガからアプリケーションを実行して、スタックしてから実行を中断してください。次に、実行中のすべてのスレッドを見て、それぞれのスタックをメモします。各スタックをたどり、各スレッドが何を待っているかを確認することができます。

+0

あなたは絶対に正しいです!私はこのようにその作業を知らなかった!だから、私は別のイベントを使用して、エンドスレッドBのスレッドを通知すると思います。この回答に+1 – TCS

+0

+1 DllMainが(システムコールとAPIコールを行うコードを含む)任意の重要でないコードパスを呼び出すと、問題が発生するだけです。 – selbie

4

@DXMが正しいと思います。 DllMainの内部で行うことができることとできないことに関するドキュメントはまれであり、見つけにくいですが、最終的には最小限に抑えておく必要があります。内部変数などを初期化してください。

もう1つは、一般的にでなければならないということです。は「regsvr32.exe」と呼ばれています。

ます。RegSvr32は、基本的にLoadLibraryでそのアドレス空間にDLLをロードする単なるラッパーで、その関数を呼び出し、DllRegisterServerという名前の関数のアドレスを取得するGetProcAddressを呼び出します。あなた自身でこの仕事をするのはもっとクリーンです(そして最終的にはもっと簡単です):

HMODULE mod = LoadLibrary(your_COM_file); 
register_DLL = GetProcAddress(mod, "DllRegisterServer"); 
if (register_DLL == NULL) { 
     // must not really be a COM object... 
} 

if (S_OK != register_DLL()) { 
     // registration failed. 
} 
+0

申し訳ありませんが、なぜ 'regsvr32'が悪いのか、独自のコードを書いている方がもっと異様なのはなぜですか? –

+0

1つの関数を呼び出すだけで、プロセス全体の作成に問題は見られませんか?ここでは4つのコード行があります。 'system'を使うコードは、少なくとも3行でなければならず、まだ動作しません。そして、あなたが作った時には、かなり多くなります(あなたが持っている以上に、*と*かなり多く)。 –

+1

'system'の言及はありません。ほとんどの場合、OPは手動でコンソールウィンドウからregsvr32.exeを実行します(私たちの多くがそうしているように)彼のCOMライブラリを登録するには、そのシステムロックのために固執しています。だから私は完全にこのCOMライブラリを登録するだけの追加ツールを実装することは役に立ちますか、それともその質問に関連するかを完全に理解していません。あなたの方法は同じことを行い、彼の図書館は同じままになるでしょう –

関連する問題