Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Wie Threads beenden und freigeben? (https://www.delphipraxis.net/191037-wie-threads-beenden-und-freigeben.html)

DCoderHH 1. Dez 2016 14:14


Wie Threads beenden und freigeben?
 
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?"

Der schöne Günther 1. Dez 2016 14:24

AW: Thread
 
Zitat:

Wenn ich das mit MyThread.FreeOnTerminate := true machen lasse
Dann ist
Delphi-Quellcode:
FreeOnTerminate
nichts für diesen Fall. Wenn ein Thread FreeOnTerminate hast solltest du nach dem Starten die Referenz nie wieder anfassen. Ab dann ist nicht mehr definiert ob die Thread-Instanz bereits freigegeben worden ist oder nicht.


Zitat:

Aber wie soll ohne FreeOnTerminate freigegeben werden?
Du hast mit deinem
Delphi-Quellcode:
EvTerminate
doch schon genau die richtige Stelle dafür! Entferne es nach wie vor aus deiner Liste und danach gibst du den TThread frei.

Zu Problem 2 würde ich deinem Thread die Logik dafür nicht mitgeben. Das
Delphi-Quellcode:
EvTerminate
ist doch auch hier eigentlich die perfekte Gelegenheit dafür!

DCoderHH 1. Dez 2016 14:32

AW: Thread
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1355151)

Zitat:

Aber wie soll ohne FreeOnTerminate freigegeben werden?
Du hast mit deinem
Delphi-Quellcode:
EvTerminate
doch schon genau die richtige Stelle dafür! Entferne es nach wie vor aus deiner Liste und danach gibst du den TThread frei.

Und wie? In OnTerminate darf kein Free aufgerufen werden.

Zitat:

Zitat von Der schöne Günther (Beitrag 1355151)
Zu Problem 2 würde ich deinem Thread die Logik dafür nicht mitgeben. Das
Delphi-Quellcode:
EvTerminate
ist doch auch hier eigentlich die perfekte Gelegenheit dafür!

Wie soll im OnTerminate der zuletzt gestartet Thread erkannt werden, wenn alle Threads gleichzeitig laufen und unterschiedlich lange Laufzeiten haben? Ein Thread kenn die anderen ja nicht und weiß in seinem OnTerminate nicht, was noch läuft und ob er der zuletzt gestartete ist.

bra 1. Dez 2016 14:49

AW: Thread
 
Du könntest nach dem Starten eines Threads alle anderen Threads aus der Threadliste löschen.

DCoderHH 1. Dez 2016 14:51

AW: Thread
 
Zitat:

Zitat von bra (Beitrag 1355160)
Du könntest nach dem Starten eines Threads alle anderen Threads aus der Threadliste löschen.

Welchen Zweck hätte das? Dann weiß ich beim Beenden des Programms nicht mehr, welche Threads noch laufen und kann sie dann nicht mehr beenden.

Klaus01 1. Dez 2016 14:57

AW: Thread
 
.. Du könntest das onTerminate Ereignis verwenden.
Damit könnte der Thread eine Nachricht absetzen wenn er beendet wird.
Die Nachricht könnte dein Haptprogramm veranlassen den Thread aus der Liste zu entfernen.

Edit.
Das machst Du doch schon - wo ist dann das Problem?

Grüße
Klaus

bra 1. Dez 2016 15:01

AW: Thread
 
Zitat:

Zitat von DCoderHH (Beitrag 1355161)
Zitat:

Zitat von bra (Beitrag 1355160)
Du könntest nach dem Starten eines Threads alle anderen Threads aus der Threadliste löschen.

Welchen Zweck hätte das? Dann weiß ich beim Beenden des Programms nicht mehr, welche Threads noch laufen und kann sie dann nicht mehr beenden.

Zitat:

Immer wenn einen neue Instanz erzeugt/gestartet wird, sollen alle anderen Threads beendet und *freigegeben* werden.
Irgendwie widersprichst du dir da gerade. Wenn ein Thread gestartet wird, geht er alle anderen Threads in der Liste durch, beendet sie und löscht sie aus der Liste. Was ist da jetzt das Problem?

DCoderHH 1. Dez 2016 15:11

AW: Thread
 
Zitat:

Zitat von bra (Beitrag 1355164)
Zitat:

Zitat von DCoderHH (Beitrag 1355161)
Zitat:

Zitat von bra (Beitrag 1355160)
Du könntest nach dem Starten eines Threads alle anderen Threads aus der Threadliste löschen.

Welchen Zweck hätte das? Dann weiß ich beim Beenden des Programms nicht mehr, welche Threads noch laufen und kann sie dann nicht mehr beenden.

Zitat:

Immer wenn einen neue Instanz erzeugt/gestartet wird, sollen alle anderen Threads beendet und *freigegeben* werden.
Irgendwie widersprichst du dir da gerade. Wenn ein Thread gestartet wird, geht er alle anderen Threads in der Liste durch, beendet sie und löscht sie aus der Liste. Was ist da jetzt das Problem?

Es ist kein Widerspruch:

Zitat:

Immer wenn einen neue Instanz erzeugt/gestartet wird, sollen alle anderen Threads beendet und *freigegeben* werden.
Dort wird und soll nicht darauf gewaret, dass die Threads wirklich beenden und freigegeben sind. Zu dem Zeiptunkt ist also nur der Wunsch an die Threads mitgeteilt worden, dass ich sie beenden möchten. Sie könnten dann aber noch laufen, während ich das Programm beenden möchte. Das Programm darf dann aber nicht beendet werden, weil die Threds noch laufen. Also muss ich hier die List haben um nachschauen zu können, ob die Threads noch laufen oder nicht.

DCoderHH 1. Dez 2016 15:15

AW: Thread
 
Zitat:

Zitat von Klaus01 (Beitrag 1355163)
.. Du könntest das onTerminate Ereignis verwenden.
Damit könnte der Thread eine Nachricht absetzen wenn er beendet wird.
Die Nachricht könnte dein Haptprogramm veranlassen den Thread aus der Liste zu entfernen.
Das machst Du doch schon - wo ist dann das Problem?

Ja ich entferne den Thread aus der Liste. Das ist aber nur die halbe Miete. Er soll auch freigegeben werden. Kann er aber nicht, da man free() in OnTerminate nicht aufrufen kann.

Sherlock 1. Dez 2016 15:16

AW: Thread
 
Threads haben zusätzlich zur Terminated noch die Finished Property. Die könntest Du abfragen, und jeden Thread, der Finished ist freigeben. Denn Terminated gibt eigentlich nur an, daß ein Thread den Terminate Befehl bekommen hat.

Und ein Thread.Free darfst Du beim entfernen aus der Liste auch machen.

Sherlock


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:35 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz