Take a look at this (pseudo) code
procedure TestASync;
begin
var lSomeIntf:=TSomeImplementor.Create as ISomeIntf;
parallel.ASync(
procedure
begin
sleep(1000); // allow the main thread to finish
MyThreadedProc(lSomeIntf);
end
);
sleep(100); // will finish before sub-thread
end;
This produces a race condition as I found out the hard way. Because TestASync
is already finished before the anonymous method gets the chance of calling MyThreadedPorc
, MyThreadedProc
is called with a nil
interface. (Which is already a lot better then some random value)
Q1: Would this also be the case for simple, non ref-counted variables (like an integer, double etc) - I suspect strongly they may get changed/return random values since they are located on the stack.
Q2: How do I get around this in a simple, clean way?
I have been fiddling with the IOmniTask
interface and other methods to start an unmonitored background thread stuff like that, but all of these appear to clutter up my code and make the source hard to understand.
Maybe something like this? :
procedure TestGenericASync;
begin
var lSomeIntf:=TSomeImplementor.Create as ISomeIntf;
parallel.ASync<ISomeIntf>(lSomeIntf,
procedure (const aSomeIntf:ISomeIntf)
begin
MyThreadedProc(aSomeIntf);
end
);
end;
As Dalija suggested, you have to work around a Delphi bug (RSP-26666) with inline variable declarations. These inline variable declarations are not captured properly by anonymous methods.
The workaround is not to use an inline variable. (or to upgrade to RS 10.4 Sydney.)
procedure TestASync;
var lSomeIntf:ISomeIntf; // declaring here works around the bug
begin
lSomeIntf:=TSomeImplementor.Create as ISomeIntf;
parallel.ASync(
procedure
begin
sleep(1000); // allow the main thread to finish
MyThreadedProc(lSomeIntf);
end
);
sleep(100); // will finish before sub-thread
end;