Autor Beitrag
NTcomputer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 33

Windows 7 x64
Delphi 2005 PE
BeitragVerfasst: Do 13.05.10 15:50 
Hallo,

ich benutze einen TMessageThread, um CPU-lastige Berechnungen auszuführen, wenn dies erforderlich ist. Jetzt kann es aber passieren, dass die aktuelle Berechnung "verworfen" werden soll, um sofort eine neue zu starten.
Meine Frage dazu ist: Wie lässt sich die derzeitige Aktion des TMessageThread SOFORT abbrechen, um gleich danach beispielsweise eine OnTerminate-Funktion aufzurufen, in der alle Variablen sauber freigegeben werden? Ich meine damit einen Befehl von außen (vom startenden Thread), nicht innerhalb des berechnenden Threads selbst, da die Berechnungen teilweise sehr lange dauern bzw. der Aufwand zu groß wäre, jedesmal auf eine Variable (Terminated) zu überprüfen. Ein Kill durch die API-Funktion TerminateThread wäre ungünstig, da sonst große Mengen nicht freigegebener Variablen im Arbeitsspeicher liegen bleiben.

Ich hoffe ihr könnt mir weiterhelfen, habe bisher noch nichts dazu passendes gefunden.

Moderiert von user profile iconNarses: Link URL-codiert.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 13.05.10 16:39 
Es gibt keine andere Möglichkeit. Ein Thread kann ausschließlich im Thread selbst abgebrochen werden. Eben wie du sagtest über Terminated.

Denn wenn ein Thread von außen abgebrochen würde, wäre der Zustand darin zu dem Zeitpunkt undefiniert. Deshalb geht das nicht. Dazu kommt noch die Freigabe der Objekte usw.

Eine einfache Prüfung auf einen Abbruch dauert eigentlich auch nicht so lange, sollte aber natürlich wenn möglich nur von Zeit zu Zeit passieren.
NTcomputer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 33

Windows 7 x64
Delphi 2005 PE
BeitragVerfasst: Fr 14.05.10 10:01 
Danke, dann weiß ich zumindest mit Sicherheit dass so wie ich mir das vorgestellt habe nicht geht.
Werde ich wohl oder übel im Thread selbst auf Terminated prüfen, auch wenn das einige Zeit dauern kann (nicht die Prüfung selbst, sondern die Berechnungen, die vor jeder Prüfung kommen).
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 14.05.10 21:06 
Du kannst aber die Priorität des abzubrechenden Threads herabsetzen. Dann wird zuerst der aktuelle Thread ausgeführt und die abzubrechenden Threads erst, wenn wieder Rechenzeit zur Verfügung steht.

Dabei musst du natürlich schauen, dass da nicht zu viele Threads parallel abzubrechen sind irgendwann, aber auf diese Weise kannst du die Folgen des verzögerten Abbruchs auf die aktuellen Berechnungen mildern.
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 15.05.10 23:38 
Geht so weit ich weiss nicht (in .NET schon).

Wenn man eine Exception in einem anderen Thread raisen könnte hättest du immer noch Probleme beim Freigeben von Speicher.
Denn wenn du sowas hast:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
ABC := TABC.Create;
try
  // ...
finally
  ABC.Free;
end;

Man geht hier davon aus, dass zwischen Create und try keine Exceptions geworfen werden. Dies wäre nicht garantiert, wenn man von einem anderen Thread aus einfach mal eine Exception in einen anderen Thread injecten könnte.

Statt auf Terminated zu prüfen könntest du theoretisch auch Speicher überschreiben und so einen Jump-Befehl "injecten". Aber sauber ist das natürlich nicht.

TerminateThread könntest du verwenden, wenn du in einem Thread nur Harmloses machst (was vermutlich eher nicht der Fall ist), d.h. wenn du alle Objekte auf dem Stack allokierst, keine Win32-Handles hast, keine CriticalSection verwendest, keine Kernel-Code ausführst usw. verwendest. Wohl eher nicht der Fall.

Oder du machst eine Multi-Prozess Architektur. Dann könntest du den Prozess abschiessen. Du kannst über Shared Memory Speicher austauschen, Messages verschicken und Semaphores verwenden.
NTcomputer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 33

Windows 7 x64
Delphi 2005 PE
BeitragVerfasst: So 16.05.10 13:05 
Danke euch für die ganzen Tipps.
@jaenicke: Das geht bei meiner Anwendung nicht, da ich ja nicht die Rechenzeit für den anderen Thread brauche, sondern im Gegenteil der Thread so schnell wie möglich abgebrochen werden soll (also Berechnungen eher schneller abschließen), weil er sofort neue Aufgaben bekommt.
@delfiphan: An das mit der Exception hatte ich auch schon gedacht, nur bekomme ich dann unter Umständen Probleme mit der Synchronisierung beim Freigeben (die benutzen Variablen werden auch von anderen Threads verwendet).
Und es ging mir ja wiegesagt um eine "saubere" Lösung.
Die Multi-Prozess-Idee ist eigentlich geeignet, nur kommt dazu dann der Mehraufwand der Verwaltung.

Ich denke, ich bleibe bei der Variablenprüfung innerhalb des Threads. Muss der Nutzer halt bisschen länger warten ;-)