thanks ahead for your time.
Simple code post at first.
code of TSubThread
TSubThread = class(TThread)
protected
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
end;
procedure TSubThread.Execute;
begin
// do nothing
end;
constructor TSubThread.Create;
begin
inherited Create(True);
Self.FreeOnTerminate:= False;
end;
code of TMainThread
TMainThread = class(TThread)
private
FCounterOK,
FCounterErr:int64;
function FGetCounterOK:Int64;
function FGetCounterErr:Int64;
protected
procedure Execute; override;
public
property CountOK:Int64 read FGetCounter;
property CountErr:Int64 read FGetCounterErr;
constructor Create;
destructor Destroy; override;
end;
function TMainThread.FGetCounterOK:Int64;
begin
result:= TInterlocked.Read(Self.FCounterOK);
end;
function TMainThread.FGetCounterErr:Int64;
begin
result:= TInterlocked.Read(Self.FCounterErr);
end;
procedure TMainThread.Execute;
const
CSTMaxThreads = 20;
var
i: Integer;
los:TArray<TSubThread>;
begin
try
while not Self.Terminated do
begin
//Create instance of TSubThread and append to DynArray
while Length(los) < CSTMaxThreads do
begin
try
l:= TSubThread.Create;
los:= los + [l];
l.Start;
TInterLocked.Increment(Self.FCounterOK);
except on E:System.SysUtils.Exception do
TInterLocked.Increment(Self.FCounterErr);
end;
end;
for i:= Length(los)-1 downto 0 do
begin
// Free thread Object
if los[i].Finished then
begin
los[i].DisposeOf;
los[i]:= nil;
Delete(los,i,1);
end;
end;
end;
finally
// MainThread Terminated, Free all.
for i := Length(los)-1 downto 0 do
begin
los[i].DisposeOf;
los[i]:= nil;
end;
delete(los,0,Length(los));
end;
end;
The creation of TSubThread raise exception after running about 1800000 ~ 2000000 times (by CounterOK and CounterErr property) on Android platform with E.ToString = "Create error: Try again."... and the same program runs perfect on Windows and IOS. Is there somewhere wrong with the code?
I'm fairly sure the problem here is that you are spawning far too many threads and running out of resources to support their existence. TThread sets finished once Execute has finished but before the actual underlying thread has been cleaned up. DisposeOf will call the destructor but this still only uses WaitFor which checks for finished and hence may still leave outstanding cleanup for the underlying thread. There have always been problems with managing the destruction of threads on all platforms and I'm pretty sure you will find this is what is happening here. For a long, long time I have resorted to always operating a thread pool with internal reuse and freeonterminate true to avoid these sorts of issues.