ich habe ein merkwürdiges Problem mit Threads. Ich habe mehrere Threads laufen, die ich ordentlich terminieren möchte, wenn ich das Formular schließe. Ich habe meistens kein Problem, die Threads zu schließen wenn ich das vorher manuell mache (im 'onClick' eines Buttons), jedenfalls nicht bei weniger als 50 Threads. Wenn ich aber das gleiche in 'FormClose' versuche, gibt es eine Exception, so dass beim Schließen eine Fehlermeldung (irgendwas mit 'notifiern') erscheint.
Meiner Meinung liegt das Problem daran, dass bei einem terminate mit 'FreeOnTerminate' das destroy noch eine zeitlang auf sich warten läßt. Aber irgendwie wird die Abarbeitungsschlange für MyThread.destroy im FormClose nicht ordentlich abgearbeitet.
Ein weiteres Problem ist, dass ich nicht vorher feststellen kann, wieviele Threads mein System verträgt. Das ist z.B. sehr unterschiedlich je nach Betriebssystem. Bei Windows (4GB Arbeitspeicher) kann ich durchaus 1000 Threads setzen, die auch alle richtig arbeiten, aber wehe, ich versuche einen davon dann zu terminieren, dann hängt es sich auf. Beim Mac (2 GB) kann ich höchstens 60 Threads setzen, dann macht es beim Erzeugen Zong (Programmabsturz). Wieviel da geht, würde ich gerne vorher irgendwie rauskriegen, so dass ich gar nicht erst zuviele Threads erzeuge.
Je mehr Threads ich habe, umso eher die Wahrscheinlichkeit, dass die Terminierung auch nur eines Threads das System einfriert. Hier die relevanten Code-Sequenzen:
Code: Alles auswählen
procedure TListThread.Execute;
var res: longint; i:integer; S:string;
begin
while not Terminated do
begin
res := basiceventWaitFor(10, _execEvent);
if res = wrSignaled then
try
basiceventResetEvent(_execEvent);
...... do something ........
finally
basiceventSetEvent(_finishEvent);
end
else
try
// wait for termination
res := basiceventWaitFor(10, _killEvent);
if res = wrSignaled then
begin
basiceventResetEvent(_killEvent);
terminate;
break;
end
else
sleep(tsleep); // tsleep = 1
finally
// ?
end;
if FSuspend then
suspend;
end;
FFinished := true;
end;
Mit der folgenden Funktion des Thread-Containers wird die Anzahl der Threads immer
auf FQuantity gesetzt. 'FQuantity = 0' bedeutet, alle Threads zu terminieren.
Code: Alles auswählen
function TThreadContainer.count:integer;
var list:TList;
begin
Result := 0;
list:= FThreadList.Locklist;
try
Result := list.count;
finally
FThreadList.Unlocklist;
end;
end;
procedure TThreadContainer.terminate;
var i:integer; list: TList; aThread:TListThread;
begin
while (count > FQuantity) do
begin
with FThreadList.LockList do
try
aThread := TListThread(list[0]);
finally
FThreadList.Unlocklist;
end;
// terminate thread
with aThread do
begin
FreeOnTerminate := true;
// Terminate; // dangerous! You can have an 'enterCriticalSection' after
// 'terminate' and then you will get stack problems. Use a '_killEvent' instead:
FFinished := false;
basiceventSetEvent(_killEvent);
// while not terminated do sleep(tsleep); // unsure! don't know why!
// waitfor; // does not work here (Unix?);
while not FFinished do sleep(tsleep); // this works pretty good!
FThreadList.remove(aThread);
// freeOnTerminate: thread is not yet completely destroyed from here
// aThread.destroy; // or freeAndNil: ---> does not work!
// aThread := nil;
end;
end;
end;
