![]() |
System.Threading: Kann man einen Task / Threadpool beenden?
Es ist im Endeffekt die gleiche wie eine meiner ersten Fragen hier:
![]() Nur diesmal auf
Delphi-Quellcode:
bezogen:
System.Threading
Kann ich einen Task, im worst case-Szenario, richtig abbrechen? Richtig tot machen? Ein einfaches Cancel() setzt vielleicht im Task-Objekt ein Flag, aber terminiert wird der entsprechende Thread dadurch nicht:
Delphi-Quellcode:
Erst schläft er sich noch richtig aus, dann wird die Zeile
procedure justTaskingThings();
var myTask: ITask; begin myTask := TTask.Run( procedure begin sleep(5000); WriteLn('Task finished'); end ); sleep(1000); WriteLn('cancelling task'); myTask.Cancel(); end;
Delphi-Quellcode:
ganz normal ausgeführt.
WriteLn('Task finished');
Ich dachte dann, es könnte helfen, explizit einen eigenen TThreadPool dafür auf zu machen und diesen dann zu beenden:
Delphi-Quellcode:
Diese Anwendung wird nie beendet werden da der TThreadPool-Destruktor ewig hängt denn er wird auf den blockierenden Thread warten.
procedure justThreadingThings();
var myTask: ITask; pool: TThreadPool; begin pool := TThreadPool.Create(); try myTask := TTask.Run( procedure begin while True do TThread.Yield(); end, pool ); myTask.Wait(100); WriteLn('cancelling task'); myTask.Cancel(); finally WriteLn('destroying pool'); pool.Free(); end; Writeln('pool is closed'); end; Ich finde keine Lösung. Gibt es überhaupt eine? |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Ja und Nein.
Ja, man kann einen Task beenden Nein einen Sleep kann ich nicht unterbrechen. Wie unterbreche ich einen Task: Indem man den Status des aktuellen Tasks abfragt mit
Delphi-Quellcode:
TTask.CurrentTask.Status
Delphi-Quellcode:
Das sollte dann auch dein Problem lösen.
procedure Foo;
begin TTask.Run( procedure begin // nur loslaufen, wenn kein Abbruch if not TTask.CurrentTask.Status = TTaskStatus.Canceled then begin end; end ); TTask.Run( procedure var LFinished: Boolean; begin // Arbeiten bis Abbruch oder Fertig while not( TTask.CurrentTask.Status = TTaskStatus.Canceled ) or LFinished do begin end; end ); end; Falls es da immer noch Probleme gibt, dann schau dir mal die Fixes für die Threading-Unit an: ![]() |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Warum sie kein CancellationToken eingebaut haben, ist mir echt unverständlich...
Sonst könnt man ja ![]() Ich würd mir wohl nen eigenes "abbrechbares" Sleep bauen, was über
Delphi-Quellcode:
checkt, obs noch weiterpennen soll.
TTask.CurrentTask.Status
|
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Das mit dem Sleep war nur ein dummes Beispiel. Bei mir ist es ein WinAPI-Aufruf der unter Umständen auf ewig blockiert. Bislang habe ich ihn in einem neuen Thread ausgeführt und wenn er nach einer bestimmten Zeit nicht fertig war habe ich ihn geplättet.
Ich dachte ich könnte dafür vielleicht jetzt System.Threading statt einer Eigenlösung nehmen, aber anscheinend nicht :-( |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Zitat:
Nein, Zaubern gehört bei denen noch nicht dazu. Und wenn ein WinApi-Aufruf blockiert, dann schaue ich auch bei der WinApi, wie man das lösen kann ;) |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Meine Geschichte zu erzählen, warum dieser Aufruf sich aufhängen kann und warum ich damit umgehen können muss führt zu weit.
Ich wollte noch nicht einmal Zauberpulver sondern nur wissen, wie man einen Task hart abbrechen kann. Und wie man einen Threadpool schließt wenn ein andauernder Task da drin ist. |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Zitat:
Aber wenn du einen Thread hart gegen die Wand fahren musst, dann wirst du mit einem Framework, was die Verwendung von Threads abstrahiert nie niemals nicht besser damit fertig, denn dieses harte gegen die Wand fahren ist nicht möglich (oder sehr schwer und bringt dann dieses Framework eher aus dem Trab). Mir geht es nur darum, dass du verstehst, warum du da kein Hexenwerk erwarten kannst. |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Alles klar. Abseits meiner spannenden Geschichte finde ich es trotzdem etwas doof, selbst ständig auf "Cancelled?" prüfen zu müssen, mir wäre lieber gewesen, der Pool (oder wer auch immer) killt den entsprechenden Thread einfach wenn man von außen sagt "Schluss jetzt"
Vielleicht habe ich auch einfach nur ein verdrehtes Weltbild. Nicht auszudenken, was ich als Politiker anstellen würde... |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Ja so ein Task kann genauso automatisch abgebrochen werden wie jede andere Methode. :roll:
Du schreibst gerade in dem Task eine große Datei, dann würgst du das von aussen ab, die Datei ist kaputt und dann fängt wieder das Geschrei an. Du bist der Programmierer und nur du kannst entscheiden, wann es sicher ist, die Aufgabe abzubrechen. Wenn du eine Aufgabe in einem Thread killen möchtest, dann kannst du
Delphi-Quellcode:
nicht verwenden. So einfach ist das. Schreib dir einen eigenen ThreadPool wo dieses harte Abwürgen funktioniert und dann sind alle glücklich - bis zu dem Tag, wo man etwas abgewürgt hat, was man besser nicht gemacht hätte - aber die Funktion ist ja da, dann benutzen wir die doch. :)
System.Threading
|
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Zitat:
|
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Zitat:
Ich wollte ja nur wissen "Kann System.Threading den bestehenden Kram ersetzen?". Die Antwort war nein. :spin2: |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Ich bin aber ehrlich gesagt immer noch nicht ganz zufrieden mit der Sache. Folgendes Beispiel, einmal ein Piep-Thread, und ein Piep-Task.
Delphi-Quellcode:
Einmal Button drücken, dann Anwendung beenden. Der Thread wird durch
unit Unit3;
interface uses System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls; type TForm3 = class(TForm) startTaskButton: TButton; startThreadButton: TButton; procedure startTaskButtonClick(Sender: TObject); procedure startThreadButtonClick(Sender: TObject); end; var Form3: TForm3; implementation uses System.Threading, System.SysUtils; {$R *.dfm} procedure proc(); const maxCount = 10; var count: Integer; begin count := 0; repeat Beep(); Inc(count); Sleep(500); until (count = maxCount); end; procedure TForm3.startTaskButtonClick(Sender: TObject); begin TTask.Run(proc); end; procedure TForm3.startThreadButtonClick(Sender: TObject); begin TThread.CreateAnonymousThread(proc).Start(); end; end.
Delphi-Quellcode:
vernünftig vorzeitig beendet. Der Task arbeitet seine zehn Piepser immer ab.
Halt
Ausprobiert mit XE7. Ist das mit 10 Seattle immer noch so? Ich finde das ehrlich gesagt gruselig. |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Ist so ... Emba hat das Abbrechen von Tasks nicht so richtig auf dem Schirm gehabt.
Generell musst du für einen abbrechbaren Task den Abbruch aber auch selber behandeln. Der anonyme Thread wird einfach so beendet, was auch nicht die feine englische Art ist :stupid: |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Natürlich sollte ich das. Mich ärgert halt ziemlich dass, sollte ich in einem Task einen dummen Fehler machen, er nie terminiert, man die Anwendung nur noch über den Taskmanager abschießen kann.
In System.Threading.pas steht sogar
Delphi-Quellcode:
, aber geprüft wird da gar nichts. Einfach Destroy() auf allen Threads aufrufen, nur leider steht da
// Check each thread to see if it is already marked for termination and/or if it is hung.
Delphi-Quellcode:
destructor TThreadPool.TBaseWorkerThread.Destroy;
begin if FRunningEvent <> nil then FRunningEvent.WaitFor(INFINITE); // This waits for the Execute to actually be called. Im Endeffekt läuft es darauf hinaus, dass ich mich nicht traue System.Threading zu verwenden und weiterhin mir selbst immer Threads zusammenfummeln werde. Echt schade. |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Destroy setzt auch Terminated auf True und genau das mußt du auch prüfen, in deinen Threads.
Bei Anonymen Threads kann man sich das Threadobjekt holen
Delphi-Quellcode:
.
if TThread.CurrentIrengwas.Terminated then raus;
|
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Ja, in einem Task kann ich prüfen ob der "Current" Thread nicht eigentlich beendet werden soll
Delphi-Quellcode:
Wie gesagt, mir geht es aber um den Fall dass im Code ein dummer Fehler ist dass er nie terminiert. Ein Deadlock, sonst was. Benutze ich die Task-Library, wird sich die Anwendung niemals beenden.
procedure proc();
begin repeat Beep(); TTask.CurrentTask.CheckCanceled(); // Bringt nichts if TThread.Current.CheckTerminated() then Break; //Das hier bringt's Sleep(500); until False; end; |
AW: System.Threading: Kann man einen Task / Threadpool beenden?
Threads/Tasks dürfen sich IMMER nur selber "definiert" beenden/anhalten.
Einfaches Beispiel: Der Thread macht grade beim Speichermanager eine Anfrage oder spielt mit Strings/Arrays rum ... wenn dabei der Thread extern beendet wird, kann das komplette Programm (alle Threads) blockieren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz