What is a proper way to terminate a thread using Delphi for iOS under ARC management?
Take this simple example:
TMyThread = class(TThread)
protected
After some digging in qc the following issues and workaround show up:
Thread parameters should be passed as const
function ThreadProc(Thread: TThread): Integer; <<-- pass_by_reference pushes
var up the ref_count.
FreeThread: Boolean;
begin
TThread.FCurrentThread := Thread;
Had you passed it as const
the ref_count would have not gone up to 3.
Normally this is not a problem, because the ref_count gets decreased on exit of the function, but here:
the function epilog is never exectued because pthread_exit() jumps out of the code.
This is only part of the solution though, quite a bit more needs to be done...
Full workaround by Dave Nottage
After much fiddling around, I've come up with this potential workaround:
Make these mods to the Classes unit: Change:
function ThreadProc(Thread: TThread): Integer;
to:
function ThreadProc(const Thread: TThread): Integer;
and add:
TThread.FCurrentThread := nil;
after this line:
if FreeThread then Thread.Free;
Override DoTerminate
in the TThread descendant, thus:
procedure TMyThread.DoTerminate;
begin
try
inherited;
finally
__ObjRelease;
end;
end;
Call the thread thus:
FMyThread.Free; // This will do nothing the first time around, since the reference will be nil
FMyThread := TMyThread.Create(True);
// DO NOT SET FreeOnTerminate
FMyThread.OnTerminate := ThreadTerminate;
FMyThread.Resume;
This (at least for me, on the device) results in the thread being destroyed on subsequent calls.
NOTE: Under ARC conditions, never declare a reference to a thread locally, because when it falls out of scope, the thread is destroyed and the Execute method is never called, not to mention other problems it causes.