2010-12-09 9 views
5

Diese Frage bezieht sich auf Delphi und XE, die Suspend and Resume explizit ablehnen. Ich habe andere Beiträge gelesen und ich habe bisher keine ähnliche Verwendung gefunden, also werde ich weitermachen und nach einer Diskussion fragen.Selbstaussetzung eines Threads in Delphi, wenn dieser nicht benötigt wird und sicher fortgesetzt wird

Was ich gerne wissen würde, gibt es eine bessere Möglichkeit, einen Thread anzuhalten, wenn es nicht benötigt wird?

Wir haben eine Delphi-Klasse, die wir seit Jahren verwenden, die im Grunde eine FIFO-Warteschlange ist, die einem Thread-Prozess zugeordnet ist. Die Warteschlange akzeptiert ein Datenobjekt im Haupt-Thread und wenn der Thread ausgesetzt wird, wird er fortgesetzt.

Als Teil des Execute-Prozesses des Threads wird das Objekt aus der Warteschlange herausgeholt und im Thread verarbeitet. Normalerweise ist dies eine Datenbanksuche.

Am Ende des Prozesses wird eine Eigenschaft des Objekts aktualisiert und als für den Hauptthread verfügbar markiert oder an eine andere Warteschlange übergeben. Der letzte Schritt des Execute-Prozesses besteht darin, zu prüfen, ob weitere Elemente in der Warteschlange vorhanden sind. Wenn es weiter geht, setzt es sich sonst aus.

Der Schlüssel ist die einzige Suspend-Aktion innerhalb der Execute-Schleife, wenn sie abgeschlossen ist, und die einzige Fortsetzung während des normalen Betriebs wird aufgerufen, wenn ein neues Element in die Warteschlange gestellt wird. Die Ausnahme ist, wenn die Queue-Klasse beendet wird.

Die Lebenslauffunktion sieht ungefähr so ​​aus.

process TthrdQueue.MyResume(); 
    begin 
    if Suspended then begin 
     Sleep(1); //Allow thread to suspend if it is in the process of suspending 
     Resume(); 
    end; 
    end; 

Das sieht auf diese

process TthrdQueue.Execute(); 
    var 
    Obj : TMyObject; 
    begin 
    inherited; 
    FreeOnTerminate := true; 
    while not terminated do begin 
     if not Queue.Empty then begin 
     Obj := Pop(); 
     MyProcess(Obj); //Do work 
     Obj.Ready := true; 
     end 
     else 
     Suspend(); // No more Work 
    end; //Queue clean up in Destructor 
    end; 

Die TthrdQueue Routine Anrufe nach dem Hinzufügen ein anderes Objekt in dem Stapel MyResume Drücken ähnlich auszuführen. MyResume ruft Resume nur dann auf, wenn der Thread gesperrt ist.

Beim Herunterfahren setzen wir terminate auf true und rufen MyResume auf, wenn es angehalten ist.

+0

Ich bin kein Experte, aber ich würde einfach Sleep (250) oder SignalObjectAndWait (siehe msdn) für eine genauere Kontrolle verwenden. –

Antwort

5

würde ich die folgende Implementierung von TthrdQueue empfehlen:

type 
    TthrdQueue = class(TThread) 
    private 
    FEvent: THandle; 
    protected 
    procedure Execute; override; 
    public 
    procedure MyResume; 
    end; 

implementation 

procedure TthrdQueue.MyResume; 
begin 
    SetEvent(FEvent); 
end; 

procedure TthrdQueue.Execute; 
begin 
    FEvent:= CreateEvent(nil, 
         False, // auto reset 
         False, // initial state = not signaled 
         nil); 
    FreeOnTerminate := true; 
    try 
    while not Terminated do begin 
     if not Queue.Empty then begin 
     Obj := Pop(); 
     MyProcess(Obj); //Do work 
     Obj.Ready := true; 
     end 
     else 
     WaitForSingleObject(FEvent, INFINITE); // No more Work 
    end; 
    finally 
    CloseHandle(FEvent); 
    end; 
end; 
+2

Er erwähnte, dass er auf Delphi XE ist, also hat er bereits Zugriff auf die generische TThreadedQueue-Klasse in der Generics.Collections-Einheit. TThreadedQueue ist eine FIFO-Warteschlange mit der Möglichkeit, Threads während des Push- und Popping-Vorgangs zu synchronisieren. – vcldeveloper

+1

Wir unterstützen immer noch eine Menge Delphi 7 Code in unseren Bibliotheken. Aber ich werde TThreadedQueue für zukünftige Bestrebungen ansehen. Ich mag die gegebene Lösung, weil sie unseren bestehenden Code leicht aktualisieren kann. –

+0

Das sieht nach einer guten Lösung aus, aber wann werden Sie MyResume anrufen? Wird die Warteschlange das tun? Und wann? Woher weiß es, welche Threads aufzuwecken sind? Oder würdest du einfach alle schlafenden Threads aufwecken, sobald ein Element am Ende der Warteschlange hinzugefügt wird? – GolezTrol

3

Statt den Faden der Aussetzung, es schlafen machen. Machen Sie es auf einem Waitable Handle blockiert, und wenn der Handle signalisiert wird, wird der Thread aufwachen.

Sie haben viele Optionen für variable Objekte, einschließlich Ereignissen, Mutex-Objekten, Semaphoren, Nachrichtenwarteschlangen und Pipes.

Angenommen, Sie möchten ein Ereignis verwenden. Machen Sie es zu einem Auto-Reset-Event. Wenn die Warteschlange leer ist, rufen Sie die Methode des Ereignisses auf. Wenn etwas anderes die Warteschlange füllt oder beenden möchte, rufen Sie die Methode SetEvent des Ereignisses an.

Ich bevorzuge Technik ist die OS-Nachrichtenwarteschlange zu verwenden. Ich würde Ihr Warteschlangenobjekt durch Nachrichten ersetzen. Schreiben Sie dann eine Standard GetMessage Schleife. Wenn die Warteschlange leer ist, wird sie automatisch blockiert, um auf eine neue Nachricht zu warten. Verwandle eine Beendigungsanfrage in eine andere Nachricht. (Die TThread.Terminate Methode ist einfach nicht eine sehr nützliche Funktion, wenn Sie tun etwas Interessantes mit Threads gestartet werden, da es nicht virtuell ist.)

+0

Ich sehe, was Sie meinen, Windows zu verwenden, um die Warteschlangen zu unterstützen. Was wir benutzt haben, ist in einer Menge existierendem Code und im Moment ist es gut genug. Aber ich werde mich definitiv für die zukünftige Arbeit damit beschäftigen, ich mag die automatische Natur davon. Vielen Dank. –

3

Es gibt eine Bibliothek in Delphi using condition variables Umsetzung der Erzeuger-Verbraucher-Warteschlange zu ermöglichen. Dieses Szenario ist eigentlich das besprochene Beispiel.

Das klassische Beispiel für Bedingung Variablen ist der Erzeuger/Verbraucher Problem. Ein oder mehrere Threads, die Producer genannt werden, produzieren Artikel und fügen sie zu einer Warteschlange hinzu. Verbraucher (andere Themen) verbrauchen Artikel, indem sie die produzierten Artikel aus der Warteschlange entfernen.

Verwandte Themen