Ich habe eine eigene Thread-Klasse erstellt: TMyThread. Wenn der Benutzer auf einen Button klickt, wird eine Instanz dieser Klasse erzeugt und gestartet. Der Benutzer kann und soll das beliebig oft und schnell tuen können.
Immer wenn einen neue Instanz erzeugt/gestartet wird, sollen alle anderen Threads beendet und *freigegeben* werden. Die neue Instanz soll sofort gestartet werden, egal was die anderen Threads noch machen, das das Beenden zeitintensiv sein kann.
Beim Beenden des Programms sollen alle noch laufenden Thread beendet werden und das Programm erst schließen, wenn alle Thread fertig sind.
Ich habe dazu folgende Lösung. Problem dabei ist, das freigeben der laufenden Threads. Wenn ich das mit MyThread.FreeOnTerminate := true machen lasse, gibt's beim Programmende in TerminateAll() die Meldung "Thread-Fehler: Das
Handle ist ungültig (X)' aufgetreten" Aber wie soll ohne FreeOnTerminate freigegeben werden?
Problem 2: Am Ende von TMyThread.Execute soll ein TNotify-Event ausgelößt werden, wenn der *zuletzt* gestartet Thread fertig ist. Evtl. hängen diese beiden Fragestellungen ja zusammen. Danke für die Hilfe!
Delphi-Quellcode:
type
TMyThread = class(TThread)
private
public
procedure Execute; override;
end;
TMyThreadList = class(TThreadList<TMyThread>)
private
public
procedure TerminateAll;
procedure AddAndStartThread(NewThread: TMyThread);
end;
TForm1 = class(TForm)
btn1: TButton;
procedure FormCreate(Sender: TObject);
procedure btn1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
procedure EvTerminate(Sender: TObject);
public
MyThreadList: TMyThreadList;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TMyThreadList.AddAndStartThread(NewThread: TMyThread);
var
i: Integer;
Items: TList<TMyThread>;
begin
Items := LockList;
try
Items.Insert(0, NewThread);
for i := Items.Count - 1 downto 1 do
TMyThread(Items[i]).Terminate;
NewThread.Start;
finally
UnlockList;
end;
end;
procedure TMyThreadList.TerminateAll;
var
i: Integer;
Items: TList<TMyThread>;
begin
Items := LockList;
try
for i := Items.Count - 1 downto 0 do
begin
TMyThread(Items[i]).Terminate;
TMyThread(Items[i]).WaitFor;
end;
finally
UnlockList;
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
MyThread: TMyThread;
begin
MyThread := TMyThread.Create(true);
MyThread.FreeOnTerminate := false;
MyThread.OnTerminate := EvTerminate;
MyThreadList.AddAndStartThread(MyThread);
end;
procedure TForm1.EvTerminate(Sender: TObject);
begin
MyThreadList.Remove(Sender as TMyThread);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
MyThreadList := TMyThreadList.Create;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyThreadList.TerminateAll;
end;
{ TMyThread }
procedure TMyThread.Execute;
var
tc: Cardinal;
a: Int64;
begin
if not Terminated then
begin
//Das nur als Beispiel für Arbeit, die der Thread macht.
while GetTickCount - tc > 10000 do
begin
if Terminated then
break;
inc(a);
end;
//Event hier, wenn das der letzte gestartete Thread ist.
end;
end;
end.
Edit: Leider kann ich den Titel dieser Frage nicht ändern. Kann das mal bitte ein Admin erledigen? Z.B. in "Wie Threads beenden und freigeben?"