Einzelnen Beitrag anzeigen

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