2012-03-26 13 views
0

私のプロジェクトにステートフルなISAPI拡張を作成する必要がありました。 TSessionList =クラス(TObject)に含まれるTSessionオブジェクトを作成しました。期限切れのセッションをクリーンアップするために、定期的にTSessionListをスキャンし、期限切れのセッションをすべて解放するクリーンアップスレッド(TThread子孫)を作成しました。ISAPI拡張TerminateExtensionスレッドデッドロック

私は、dprメイン実行ブロックにTSessionListとCleanupThreadを作成します。それはまあまあです。しかし、実際に私は、CleanupThreadの破壊をどこに置くべきかわかりません。ドキュメントから、ISAPI拡張機能は、拡張機能がアンロードされる直前に呼び出されるTerminateExtensionをエクスポートする必要があることがわかりました。コースのデフォルトのDelphi ISAPI拡張は、そのような関数をエクスポートします。だから私は "overriden it" =私のセッションオブジェクトを解放し、次にデフォルトのISAPIAPP.TerminateExtensionProcを呼び出すTerminateExtensionをエクスポートしました。

ここでは次のように、それがどのように見えるかです:CleanupThread破壊がDoneSessionsで、このように行われている

function TerminateExtension(dwFlags: DWORD): BOOL; stdcall; 
begin 
    DoneSessions; 
    Result:= ISAPIApp.TerminateExtension(dwFlags); 
end; 

exports 
    GetExtensionVersion, 
    HttpExtensionProc, 
    TerminateExtension; 

begin 
    CoInitFlags := COINIT_MULTITHREADED; 
    Application.Initialize; 
    InitSessions; 
    Application.CreateForm(TSOAPWebModule, SOAPWebModule); 
    Application.Run; 
end. 

begin 
    CleanupThread.Free; 
    SessionList.Free; 
end; 

CleanupThreadはのTThreadの簡単な子孫であるので、何のために見ていませんその破壊コードに特有のものです。

問題は、TerminateExtensionがCleanupThread.Freeでフリーズすることです。さらにデバッグすると、TThread.WaitForでフリーズが発生することがわかりました。私はある種のスレッドデッドロック= ISAPIワーカースレッドが私の拡張機能が終了するのを待っている必要があると思われます。これはTThread.WaitForで待機し、メインスレッドがシグナルを出すのを待ちます。

私はこの状況を克服してCleanupThread.Terminateを呼び出し、直接WaitForSingleObject(またはMultiple ???)を使用して最後に解放することができます。しかし、それはちょっと聞こえる...非標準です。

私の質問は:どのようにすればいいですか?スレッドデッドロックを避けるために、ISAPI拡張のサポートスレッドをフリーズ(Terminate - WaitFor - Destroy)する必要がありますか?

ところで、私はすでに標準DLLで同じものを見つけました。任意のthread.WaitForをdllアンロードプロシージャに置くと、メインアプリケーションはライブラリアンロード時にフリーズします。うまくいけば、同じ質問/答えがここに適用されます。

答えて

0

たとえば、freeを呼び出す前にスレッドの終了を通知するようにしてください。

CleanupThread.Terminate; 
if CleanupThread.Waitfor(60000)<>WR_Abandoned then //wait for 60sec for cleanup 
    CleanupThread.free 
else 
    //do something sensible on timeout or error 

しかし、クリーンアップスレッドが何をしようとしているのかわからなくても、何がデッドロックを引き起こす可能性があるのか​​は分かりません。これらは競合状態の結果であることがよくあります。特に、&のwaitforがタイムアウトすると、スレッドが何をしているのかを指定する必要があります。

ハッキング(マルチスレッドのための良い方法ではない)として、winapi呼び出しTERMINATETHREAD(Windows単位)を使用してスレッドを強制終了することができます。

TerminateThread(CleanupThread.handle,0); 

これはスレッドで即時終了を強制するだけでなく、どのスレッドのクリーンアップが行われていない手段として - 場合は、これはあなたのスレッドコードに完全に依存している - TTHREAD.TERMINATEを呼び出すと、スレッドが終了することを保証するものではないことを覚えておいてください何かがスレッドをブロックしていて、通常の方法で終了しません。 TerminateThreadはこれを解決することができます。コードを犠牲にして、リソースの解放や他のスレッドが何であるかを考慮しないで停止するだけです。

関連する問題