Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn! (https://www.delphipraxis.net/176205-exception-ohne-wirklichen-ausloeser-treibt-mich-den-wahnsinn.html)

Der schöne Günther 20. Aug 2013 19:58

AW: Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn!
 
Zitat:

Wenn ich Dich richtig verstehe, dürfen im Prinzip 1000 verschiedene Threads problemlos gleichzeitig tmpBestellung.ID auslesen, wenn diese irgendwie an das Objekt kommen. Was passiert, wenn dieses Objekt eine public-Variable/Objekt von frmMain ist, z.B. frmMain.AktuelleBestellung (nur als Beispiel!)?
Nur weil es ein Feld einer Form ist, heißt es nicht, dass man es nicht anfassen darf. Mit "VCL-Dinge" meinte ich bsp. Label aktualisieren, Komponenten verstecken. meineForm.verweisAufIrgendetwasAnderes kann man problemlos aus anderen Threads anfassen. Nur nicht vergessen: Wenn sich mehrere Threads für irgenetwas interessieren könnten, muss das entsprechend geschützt werden.

Zitat:

Darf ich in CriticalSection auf VCL-Objekte zugreifen? Ich muss mich da mal einlesen.
Ein kritischer Abschnitt ist keine Magie. Synchronisationshilfen wie KA oder anderes bringt nur etwas, wenn sich alle Teilnehmer auch daran halten. Und die Delphi VCL-Logik wird sich sicher nicht an deinen selbst eingeführten KA halten.

Wenn du wirklich in einem Thread direkt etwas an der VCL-Oberfläche ändern musst, dann ist dazu
Delphi-Quellcode:
TThread.Synchronize(..)
bzw.
Delphi-Quellcode:
TThread.Queue(..)
da.

Zitat:

Darf ich denn Variable, die garantiert nur vom Thread geschrieben werden (z.B. blTerminated) jederzeit ohne CriticalSelection schreiben, oder muss ich, weil ich mit frmMain im 10ms Takt "if LoadSave.blTerminated" beispielhaft überprüfe, ob der Thread fertig beendet ist unbedingt die CriticalSelection verwenden? frmMain ließt ja nur!?
Könnte man glauben, das reicht aber leider nicht. In der Praxis ist die Wahrscheinlichkeit, dass es da knallt zwar extrem gering, aber wie gesagt (es sind eigentlich wirklich nur die zwei Regeln): Sobald sich mehr als ein Thread dafür interessiert: Absichern.
Zitat:

Zitat von Olli73 (Beitrag 1225570)
Bei boolean gibt es (wahrscheinlich) keine Probleme. [...]

Auf SO gab es vor ein paar Tagen genau das Problem, dass eine Integer-Variable in einem Thread hochgezählt wurde und der Hauptthread griff nur lesend zu. Hat auf Dauer auch nicht geklappt. Ich würde nie davon ausgehen, dass da irgendetwas atomar abläuft. Auch bei Boolean nicht.

Außerdem wiederhole ich gerne noch einmal mein "Du machst es dir unnötig kompliziert": Dein TThread-Objekt hat ganz komfortabel schon Eigenschaften wie
Delphi-Quellcode:
Terminated
oder
Delphi-Quellcode:
Finished
. Die kannst du einfach lesen und brauchst dir keine Sorgen machen. Und nichts eigenes erfinden.

berens 20. Aug 2013 20:14

AW: Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn!
 
Günther: Bin mir nicht sicher, aber ich glaube in Delphi 2007 gibt es TThread.Finished nicht.

TThread.Terminate setzt ja nur die Boolean-Variable des Threads auf Terminated, ich kann ja (ohne das Finished von oben) nicht so einfach ohne eigene Variable feststelle, ob .Execute nun ordnungsgemäß beendet wurde?

Klar, es gibt Event.WaitFor. Damit habe ich noch nie gearbeitet, und es scheint doch unverhältnismäßig komplizierter zu sein, als eine einfache Booleanvariable im Thread.

Zumindest das Beispiel aus der OH ist nicht wirklich selbsterklärend:
Delphi-Quellcode:
Event1.ResetEvent(); { Ereignis vor der Ausführung der Threads zurücksetzen }
for i := 1 to Counter do
TaskThread.Create(False); { Aufgaben-Threads erzeugen und ausführen }
if Event1.WaitFor(20000) <> wrSignaled then
raise Exception;
{ nun den Haupt-Threads fortsetzen Alle Aufgaben-Threads sind beendet }
Woher weiß z.B. das Event, dass es auf meinen Thread warten soll? Hier in dem Beispiel werden mehrere Threads erzeugt. Woher weiß das Event, dass alle fertig sind? Wird wrSignaled immer von Thread nach der Beendigung von Terminate gesetzt? Fragen über Fragen.

Weiterhin Danke an Alle! :)

Der schöne Günther 20. Aug 2013 20:30

AW: Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn!
 
Falls es die
Delphi-Quellcode:
Finished
-Property noch nicht gibt, dann doch wenigstens das
Delphi-Quellcode:
onTerminate
-Ereignis? Das wird ausgeführt, wenn der Thread seine Execute-Methode verlassen hat. Als Bonus wird die Methode bereits im Kontext des Hauptthreads ausgeführt, du kannst also schon gefahrlos an VCL-Komponenten herumwerkeln.

Darin kannst du ja dann auch einfach eine
Delphi-Quellcode:
meineForm.derThreadIstFertig := True
setzen.

Uwe Raabe 20. Aug 2013 21:21

AW: Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn!
 
Zitat:

Zitat von berens (Beitrag 1225565)
Uwe: Erklär mir doch bitte noch in 1-2 Sätzen, wie ich den Thread ohne Aufruf eines Synchronize abbrechen kann.

Innherhalb des Execute fragst du regelmäßig Terminated ab. Wenn du von außerhalb den Thread beenden willst, rufst du MyThread.Terminate (oder wie die Variable auch heißt, in der du dir Thread-Instanz ablegst) auf. Das ist der empfohlene Weg.

Willst du im Hauptthread auf das Ende von MyThread warten, hilft MyThread.WaitFor (gegebenfalls mit einem Timeout).

Olli73 20. Aug 2013 21:26

AW: Exception ohne wirklichen Auslöser treibt mich in den Wahnsinn!
 
Zitat:

Zitat von berens (Beitrag 1225576)
Zumindest das Beispiel aus der OH ist nicht wirklich selbsterklärend:
Delphi-Quellcode:
Event1.ResetEvent(); { Ereignis vor der Ausführung der Threads zurücksetzen }
for i := 1 to Counter do
TaskThread.Create(False); { Aufgaben-Threads erzeugen und ausführen }
if Event1.WaitFor(20000) <> wrSignaled then
raise Exception;
{ nun den Haupt-Threads fortsetzen Alle Aufgaben-Threads sind beendet }
Hier in dem Beispiel werden mehrere Threads erzeugt. Woher weiß das Event, dass alle fertig sind?

Der Letzte macht das Licht aus ;)
Das steht weiter oben im Beispiel der OH:

Delphi-Quellcode:
 procedure TDataModule.TaskTerminateThread(Sender: TObject);
 begin
   ...
   CounterGuard.Acquire; { Zähler mit einer Sperre belegen }
   Dec(Counter);  { Wert der globalen Zählervariable verringern }
   if Counter = 0 then
     Event1.SetEvent; { Signalisieren, ob es der letzte Thread ist }
   Counter.Release; {Sperre vom Zähler entfernen}
   ...
 end;
Der Counter wird im OnTerminate eines jeden Threads heruntergezählt (mit critical section versteht sich!). Wenn 0 erreicht ist, weiß der Thread, dass er der letzte ist und macht das Lich aus (SetEvent).


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:03 Uhr.
Seite 3 von 3     123   

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