I was wrong. 1 Thread is 1MB, 100 is 100MB, 1000 is 1GB
Why would 1 thread be equal to 1Mb?
I thought the default stack size of a thread is 4Mb.
So we're looking into 500 threads for 32-bit (2Gb max) machine.
(TThread class has a StackSize parameter. You might want to play with it in order to see how far you can go)
This test is the localization of the problem...
The multithreading app stops working after a certain amount of time, may be 1 day, may be week. App connecting to database and making queries by requests of hardware stations. No heavy load, normal number of threads, randomly crashed on several pc
Why would you suspect the number of threads then? If the number of threads used in the app are "normal"?
You might need to add extra logs entries into the app.
I still can't figure out why the error occurs on some PC. In my case, threads are created and destroyed, there can be no more than 500 threads at the same time. Everything works for me locally without failures, on the test machine after a while the error of creating new threads starts to appear
It is possible that your experiencing the different context-switching time.
The more threads you have the more time is wasted to switch between the different threads.
I'm assuming your machine is fast enough to create and dispose the necessary amount.
The test machine might be lagging on executing the launched threads at some point.
I think if you want to text the maximum number of threads you need to modify your test.
Instead of "Sleep(100)" all every launched thread should wait for some event to be signaled.
In this case you're not risking the context switching lag.
Once your main thread cannot spawn new threads anymore you simply singal the even and let all the threads to finish. In this case, I'm expecting the "max number" of threads to be identical on your and the test machine.
program project1;
{$ifndef fpc}{$APPTYPE CONSOLE}{$endif}
uses
SysUtils, Classes, syncobjs;
type
TTestThread = class(TThread)
procedure Execute; override;
end;
var
showStopper : TEvent;
procedure TTestThread.Execute;
begin
showStopper.WaitFor(INFINITE);
end;
procedure RunTest(count: integer; stackSize: integer);
var
list : TList;
Thread : TThread;
j, no: integer;
begin
list := TList.Create;
showStopper := TEvent.Create(nil, true, false,'');
try
no := 0;
try
for j := 1 to count do
begin
Thread := TTestThread.Create(true, stackSize);
list.Add(thread);
inc(no);
Thread.FreeOnTerminate := false;
Thread.Start;
if (j mod 10 = 0) then writeln(j,' threads created')
end;
except
on x: exception do
writeln('failure while creating a thread: ', j,' ',x.message);
end;
finally
writeln('cleaning up');
showStopper.SetEvent;
for j := 0 to list.Count-1 do begin
TThread(List[j]).WaitFor;
TThread(List[j]).Free;
end;
list.Free;
showStopper.Free;
writeln('clean is done');
end;
end;
var
part : integer;
stackSize : integer;
st : double;
begin
try
part := 1000;
stackSize := DefaultStackSize;
if ParamCount>0 then part := StrToIntDef(ParamStr(1), 0);
if ParamCount>1 then begin
st := StrToFloatDef(ParamStr(2), -1);
if st>0 then stackSize := Round(1024*1024*st)
else stackSize := DefaultStackSize;
end;
writeln('Threads = ', part);
writeln('stackSize = ', stackSize/1024/1024:0:2,'Mb');
RunTest(part, stackSize);
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end;
end;
end.
If you run this app like this:
test 1000 1
(spawning 1000 threads with 1Mb stack size) all of them should be created.