2017-02-17 4 views
5

Ich habe ein Programm, das einen Thread verwendet, der einige Arbeit ausführt. Der Thread sollte einen anderen Thread (in diesem Beispiel den Hauptthread) über den Fortschritt informieren. Wenn ich Synchronize() verwenden, um die Synchronisierung durchzuführen, funktioniert alles wie erwartet. Wenn ich mit dem Haupt-Thread zu synchronisieren und die für variable veröffentlichen und es in eine Liste bekommt jeder Wert richtig in meine ListBox gedruckt setzen:Behandlung der lokalen Variablen in anonymer Prozedur an TThread.Queue übergeben

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Synchronize(
     procedure() 
     begin 
     FireEvent(i); 
     end); 
    end; 
end; 

Ausgang: 1, 2, 3, 4, 5. .. 1000

Wenn ich Queue(), um die Synchronisation der Ausgang wie auszuführen nicht zu erwarten:

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Queue(
     procedure() 
     begin 
     FireEvent(i); 
     end); 
    end; 
end; 

Ausgang: 200, 339, 562, 934, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, [...]

Was geschieht hier? Nach meinem Verständnis sollte das anonyme Verfahren die Variable "i" erfassen?

+0

PS: Ich weiß, dass es nicht viel Sinn macht, die Benutzeroberfläche so häufig zu aktualisieren. Ich möchte nur wissen, was den variablen Inhalt ändert, obwohl die Anonymous-Methode den Wert erfassen sollte. –

+1

Sie erfassen die Variable. Aber Sie versuchen, den "Wert" zu erfassen. Sie müssen also für jede Iteration der Schleife eine neue Variable erstellen und diese erfassen. Dies erfordert einen neuen Stapelrahmen und somit einen Funktionsaufruf. Was zu dem Code in LURDs Antwort führt. –

Antwort

5

Die anonyme Prozedur erfasst die Variablenreferenz. Dies bedeutet, dass der Wert beim Ausführen des anonymen Verfahrens nicht festgelegt ist.

Um einen Wert zu erfassen, werden Sie es zu einem einzigartigen Rahmen wie diese wickeln müssen:

Type 
    TWorkerThread = class (TThread) 
    ... 
    function GetEventProc(ix : Integer): TThreadProcedure; 
    end; 

function TWorkerThread.GetEventProc(ix : Integer) : TThreadProcedure; 
// Each time this function is called, a new frame capturing ix 
// (and its current value) will be produced. 
begin 
    Result := procedure begin FireEvent(ix); end; 
end; 

procedure TWorkerThread.Execute; 
var 
    i: Integer; 
begin 
    inherited; 

    for i := 1 to 1000 do 
    begin 
    Queue(GetEventProc(i)); 
    end; 
end; 

Siehe auch Anonymous methods - variable capture versus value capture.

+0

Das kompiliert nicht ... –

+0

Sollte 'Queue (EventWithValue (i))' und 'EventWithValue' sollte eine' TThreadProcedure' zurückgeben. Zumindest würde ich das tun. –

+0

Lesen Sie die Dokumentation: [Anonyme Methoden in Delphi] (http://docwiki.embarcadero.com/RADStudio/de/Anonymous_Methods_in_Delphi), insbesondere [Anonymous Methods Variable Binding] (http://docwiki.embarcadero.com/RADStudio/) de/Anonymous_Methods_in_Delphi # Anonymous_Methods_Variable_Binding). –

Verwandte Themen