I have a program which uses a Thread that performs some work. The thread should notify another thread (in this example the main thread) of the progress.
If I use Synchronize() to perform the synchronization everything works as expected. If I synchronize with the main thread and publish the for-variable and put it into a list every single value get's printed correctly into my ListBox:
procedure TWorkerThread.Execute;
var
i: Integer;
begin
inherited;
for i := 1 to 1000 do
begin
Synchronize(
procedure()
begin
FireEvent(i);
end);
end;
end;
Output: 1, 2, 3, 4, 5 ... 1000
If I use Queue() to perform the synchronization the output is not as expected:
procedure TWorkerThread.Execute;
var
i: Integer;
begin
inherited;
for i := 1 to 1000 do
begin
Queue(
procedure()
begin
FireEvent(i);
end);
end;
end;
Output: 200, 339, 562, 934, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, [...]
What's happening here? As of my understanding the anonymous procedure should capture the variable "i"?
The anonymous procedure captures the variable reference. This means that the value is undetermined when the anonymous procedure runs.
In order to capture a value, you will have to wrap it into a unique frame like this:
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;
See also Anonymous methods - variable capture versus value capture.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With