2012-03-26 8 views
0

Ich musste StateAPI-Erweiterung für mein Projekt erstellen. Ich habe erfolgreich ein TSession-Objekt erstellt, das in einer TSessionList = class (TObject) enthalten ist. Zur Bereinigung abgelaufener Sitzungen habe ich einen Aufräum-Thread (TThread-Nachfolger) erstellt, der TSessionList regelmäßig überprüft und alle abgelaufenen Sitzungen freigibt.ISAPI Extension TerminateExtension Thread Deadlock

Ich erstelle die TSessionList und die CleanupThread im Hauptausführungsblock dpr. Was gut ist. Aber eigentlich bin ich mir nicht sicher, wo ich die Zerstörung von CleanupThread hinlegen soll. Aus der Dokumentation habe ich festgestellt, dass die ISAPI-Erweiterung TerminateExtension exportieren muss, die unmittelbar vor dem Entladen der Erweiterung aufgerufen wird. Die standardmäßige Delphi-ISAPI-Erweiterung exportiert natürlich eine solche Funktion. Also habe ich es "überschrieben" = exportierte meine TerminateExtension, die meine Sitzungsobjekte freigibt und dann den Standard ISAPIAPP.TerminateExtensionProc aufruft.

Hier ist, wie es aussieht:

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. 

Die CleanupThread Zerstörung wird in DoneSessions diese Weise getan:

begin 
    CleanupThread.Free; 
    SessionList.Free; 
end; 

Die CleanupThread ist einfach Nachkomme TThread, so schauen Sie nicht für alles spezifisch in seinem Zerstörungscode.

Das Problem ist, dass die TerminateExtension nur in CleanupThread.Free einfriert. Weiter Debuggen fand ich, dass das Einfrieren im TThread.WaitFor passiert. Ich vermute, dass es eine Art Thread-Deadlock geben muss = ISAPI-Worker-Thread wartet auf die Beendigung meiner Erweiterung, die in TThread.WaitFor wartet, damit der Haupt-Thread signalisiert wird (oder was auch immer).

Ich weiß, ich könnte diese Situation zu überwinden, CleanupThread.Terminate aufrufen, dann direkte WaitForSingleObject (oder Multiple ???) und schließlich befreien. Aber das klingt ein bisschen ... nicht standardgemäß.

Daher ist meine Frage: Wie und wann sollte ich Free (Beenden - WaitFor - Destroy) Support-Threads in ISAPI-Erweiterung, Thread-Deadlock zu vermeiden?

BTW: Ich habe bereits das gleiche in der Standard-DLL gefunden. Wenn Sie thread.WaitFor in den Dll Unload-Prozess setzen, friert Ihre Haupt-App nur beim Entladen der Bibliothek ein. Also die gleiche Frage/Antwort gilt hoffentlich hier.

Antwort

0

Sie sollten versuchen, den Thread zu beenden, bevor Sie frei anrufen, zum Beispiel;

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

Aber ohne zu wissen, was genau ist der Bereinigungsthread schwer es ist zu sagen zu tun versuchen, was zu einem Deadlock verursachen könnte. Oft sind diese das Ergebnis von Race Conditions, besonders wenn ein & waitfor mal abläuft, also muss man angeben was der Thread gerade macht.

Als Hack (und keine gute Praxis für Multithreading) können Sie einen Thread zwingen, mit dem Winapi-Aufruf TERMINATETHREAD (in der Windows-Einheit) zu beenden;

TerminateThread(CleanupThread.handle,0); 

Da dies einen sofortigen Ausstieg auf dem Faden zwingt sondern bedeutet auch kein Gewinde Bereinigung durchgeführt wird - denken Sie daran, dass TTHREAD.TERMINATE Aufruf garantiert nicht, dass ein Thread verlassen wird - das ist völlig abhängig von der Thread-Code, wenn etwas blockiert deinen Thread, dann wird es nicht auf normale Weise beendet. TerminateThread kann dies lösen, auf Kosten des Codes, der einfach stoppt, wo es ist, ohne Rücksicht auf Ressourcenfreisetzung oder was andere Threads vorhaben.