AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Wie Threads beenden und freigeben?

Ein Thema von DCoderHH · begonnen am 1. Dez 2016 · letzter Beitrag vom 1. Dez 2016
Antwort Antwort
Seite 1 von 2  1 2      
DCoderHH

Registriert seit: 4. Feb 2015
Ort: Hamburg
84 Beiträge
 
Delphi 10 Seattle Professional
 
#1

Wie Threads beenden und freigeben?

  Alt 1. Dez 2016, 14:14
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?"

Geändert von TBx ( 1. Dez 2016 um 22:10 Uhr) Grund: Titel auf Wunsch des TE geändert
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Thread

  Alt 1. Dez 2016, 14:24
Zitat:
Wenn ich das mit MyThread.FreeOnTerminate := true machen lasse
Dann ist 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 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 EvTerminate ist doch auch hier eigentlich die perfekte Gelegenheit dafür!
  Mit Zitat antworten Zitat
DCoderHH

Registriert seit: 4. Feb 2015
Ort: Hamburg
84 Beiträge
 
Delphi 10 Seattle Professional
 
#3

AW: Thread

  Alt 1. Dez 2016, 14:32

Zitat:
Aber wie soll ohne FreeOnTerminate freigegeben werden?
Du hast mit deinem 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.

Zu Problem 2 würde ich deinem Thread die Logik dafür nicht mitgeben. Das 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.
  Mit Zitat antworten Zitat
bra

Registriert seit: 20. Jan 2015
711 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#4

AW: Thread

  Alt 1. Dez 2016, 14:49
Du könntest nach dem Starten eines Threads alle anderen Threads aus der Threadliste löschen.
  Mit Zitat antworten Zitat
DCoderHH

Registriert seit: 4. Feb 2015
Ort: Hamburg
84 Beiträge
 
Delphi 10 Seattle Professional
 
#5

AW: Thread

  Alt 1. Dez 2016, 14:51
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.
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Thread

  Alt 1. Dez 2016, 14:57
.. 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
Klaus
  Mit Zitat antworten Zitat
bra

Registriert seit: 20. Jan 2015
711 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#7

AW: Thread

  Alt 1. Dez 2016, 15:01
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?
  Mit Zitat antworten Zitat
DCoderHH

Registriert seit: 4. Feb 2015
Ort: Hamburg
84 Beiträge
 
Delphi 10 Seattle Professional
 
#8

AW: Thread

  Alt 1. Dez 2016, 15:11
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.
  Mit Zitat antworten Zitat
DCoderHH

Registriert seit: 4. Feb 2015
Ort: Hamburg
84 Beiträge
 
Delphi 10 Seattle Professional
 
#9

AW: Thread

  Alt 1. Dez 2016, 15:15
.. 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.
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.763 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Thread

  Alt 1. Dez 2016, 15:16
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
Oliver
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:28 Uhr.
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