6


2

私たちはDUnitを使ってテストする、かなり成熟したCOM DLLを持っています。 最近のテストの1つでは、いくつかのスレッドを作成し、それらのスレッドからオブジェクトをテストします。 このテストは、guiフロントエンドを使用してテストを実行すると問題なく動作しますが、コンソールアプリケーションとして実行するとハングします。 これがテストの結果の簡単な疑似ビューです。

SetupTest; fThreadRefCount:= 0; //アクティブなスレッド数Thread1:= TMyThread.Create(True); Inc(fThreadRefCount); Thread1.OnTerminate:= HandleTerminate; // HandleOnTerminateは、fThreadRefCount Thread3をデクリメントします。Thread3:= TMyThread.Create(True); Inc(fThreadRefCount); Thread2.OnTerminate:= HandleTerminate; // HandleOnTerminateは、fThreadRefCount Thread3をデクリメントします。Thread3:= TMyThread.Create(True); Inc(fThreadRefCount); Thread3.OnTerminate:= HandleTerminate; // HandleOnTerminateはfThreadRefCountをデクリメントする

Thread1.Resume; Thread2.Resume; Thread3.Resume;

fThreadRefCount> 0の間はApplication.ProcessMessagesを実行します。

OnExecuteでは何もしないで試したので、実際にテストしているコードではないと確信しています。 コンソールでは、fThreadRefCountがデクリメントされることはありませんが、GUIアプリケーションとして実行した場合は問題ありません。

私の知る限りでは、OnTerminateイベントは呼び出されません。

2 Answer


8


もっとデータを提供する必要があります。

OnTerminateはSynchronizeを介して呼び出されるため、どこかの時点でCheckSynchronizeを呼び出す必要があります。 Application.ProcessMessagesは通常これを行いますが、VCLがどのように初期化されたかによっては、Synchronizeメカニズムがコンソールアプリケーションに完全に接続されていない可能性があります。

いずれにせよ、このプログラムは私のマシンでは期待通りに動作します。

Windows、SysUtils、Classes、Formsを使用します。

var threadCount:整数。

type TMyThread = class(TThread)パブリックプロシージャーExecute;オーバーライド;クラス手続きGo;クラス手続きHandleOnTerminate(送信者:TObject);終わり;

TMyThread.Execute;プロシージャ始めと終わり

クラスプロシージャTMyThread.Go。関数MakeThread:TThread。開始結果:= TMyThread.Create(True); Inc(threadCount); Result.OnTerminate:= HandleOnTerminate;終わり; var t1、t2、t3:TThread。 t1:= MakeThreadを開始します。 t2:= MakeThread; t3:= MakeThread; t1.Resume; t2.Resume; t3.Resume; threadCount> 0の間はApplication.ProcessMessagesを実行します。終わり;

クラスプロシージャーTMyThread.HandleOnTerminate(送信者:TObject); InterlockedDecrement(threadCount)を開始します。終わり;

TMyThread.Goを試してみてください。 eを除く:Exception do Writeln(e.Message);終わり;終わり。


5


Barryが正しく指摘したように、CheckSyncronizeが呼び出されない限り、Synchronizeは呼び出されず、synchronizeが呼び出されない場合は、OnTerminateイベントは発生しません。 起こっているように思われるのは、私が自分のユニットテストをコンソールアプリケーションとして実行すると、メッセージキューにメッセージがなく、したがってProcessmessagesから呼び出されるApplication.ProcessMessageがcheckSynchronizeを呼び出すことが決してないということです。 ループを次のように変更して問題を解決しました。

fThreadRefCount> 0の間はApplication.ProcessMessagesを開始します。 CheckSynchronize;終わり;

それは今コンソールとGUIモードの両方で動作します。

wakeupmainthreadフック全体が正しく設定されているようです。 checksynchronizeをトリガーするWM_NULLメッセージを投稿するのは、このフックです。 コンソールアプリではそれほどうまくいきません。

その他の調査

同期するために_does_が呼び出されるようにします。 DoTerminateはSynchronize(CallOnTerminate)を呼び出しますが、そこに行があります。

WaitForSingleObject(SyncProcPtr.Signal、Infinite);

これはただ待つだけです。

だから私の上記の修正はうまくいくが、もっと深いことがある。