Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Mal wieder Threads (https://www.delphipraxis.net/164268-mal-wieder-threads.html)

DelTurbo 5. Nov 2011 10:01

Mal wieder Threads
 
Hi,
ich habe nur eine kurze frage. Ich erstelle mit TJvMTThread einen Thread, der über Postmessage mit dem programm redet, um ausgaben zu machen. Leider musste ich feststellen das das öfters mal in die hose geht. Leider weiss ich nicht warum. Ich bekomme nie 2x die gleiche fehler meldung. Aber es sind immer ungültige Pointer. z.b. mal in StrLen oder Minimizename usw.

Ist es besser wenn man Threads wie folgt macht? Weil von da kenne ich das mit dem Postmessage. Oder ist das mit dem Post falsch bei TJvMTThread?

Danke im voraus

Delphi-Quellcode:
const
  THREAD_TERMINATE                = $0001;
  THREAD_SUSPEND_RESUME           = $0002;
  THREAD_GET_CONTEXT              = $0008;
  THREAD_SET_CONTEXT              = $0010;
  THREAD_SET_INFORMATION          = $0020;
  THREAD_QUERY_INFORMATION        = $0040;
  THREAD_SET_THREAD_TOKEN         = $0080;
  THREAD_IMPERSONATE              = $0100;
  THREAD_DIRECT_IMPERSONATION     = $0200;
  THREAD_SET_LIMITED_INFORMATION  = $0400;
  THREAD_QUERY_LIMITED_INFORMATION = $0800;
  THREAD_ALL_ACCESS               = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $03FF;

function OpenThread(dwDesiredAccess: DWord;
                    bInheritHandle: Bool;
                    dwThreadId: DWord): DWord; stdcall; external 'kernel32.dll';

{##############################################################################}

procedure StartNewThread;
begin
    ThreadHandle:=BeginThread(nil, 0, @MyThread,@MyID, 0, ThreadID);
    if ThreadHandle<>0 then CloseHandle(ThreadHandle);
end; {StartNewThread}

jaenicke 5. Nov 2011 10:24

AW: Mal wieder Threads
 
Ich weiß nicht was die JEDI-Variante anders macht als ein normaler TThread (den ich immer benutze), aber dort ist das mit PostMessage usw. kein Problem.

Die Fehlerbeschreibung hört sich eher danach an als ob du FreeOnTerminate und Resume benutzt und das ist böse, insbesondere in der Kombination...
Denn die Fehlermeldung bedeutet meistens, dass ein Objekt beim Zugriff darauf schon freigegeben war, oft wird da gerade versucht das Objekt erneut freizugeben.

Wie sieht dein Thread denn aus? Und wie benutzt du ihn?

Und FastMM kann dir auch genauer sagen, ob meine Vermutung bezüglich der Freigabe schon freigegebener Objekte stimmt (wobei es für multi-threaded Anwendungen nicht immer gut funktioniert).

DelTurbo 5. Nov 2011 10:39

AW: Mal wieder Threads
 
Öhm, der Thread macht eigentlich nicht viel. Er schreibt daten in eine MySql. Nun fällt mir grade ein, das ich in dem Thread auch Threads erstelle und benutze. Die machen aber keine ausgbabe, sondern erzeugen bis zu 5 Querys auf die MySql. Diese bis zu 5 Threads werden ohne Jvcl gemacht. So wie oben geschrieben.

In der schleife (dem eigentlichen Thread) wird immer alle 100ms ausgegeben welches file er grade bearbeitet, wieviel es ingestamt sind und noch 2-3 ausgaben. Das mache ich nichtmehr in dem Thread mit z.b.

Form1.Label1.Caption:='doedel';

Sondern dafür habe ich eine extra routine die mit Postmessage aufgerufen wird.

Lasse ich nun die diese ausgaben weg, scheppert es nichtmehr. Das blöde ist, das passiert immer erst nach ein paar minuten, womit das testen zur qual wird.

Luckie 5. Nov 2011 11:37

AW: Mal wieder Threads
 
Du darfst auf VCL Elemente des Hauptthreads nur über Synchronize zugreifen, nie direkt, weil die VCL nicht threadsafe ist.

DelTurbo 5. Nov 2011 11:49

AW: Mal wieder Threads
 
Mache ich doch nicht. Oder ist das Postmessage auch falsch? Wenn ja, eine zeile Source wäre nett. :-D

Nochwas anderes, der unterschied zw. PostMessage und SendMessage ist doch nur, das SendMessage wartet bis die aufgerufene sub fertig ist, wobei Post das einfach "einreiht" und sofort wieder da ist. Ist das richtig?

Luckie 5. Nov 2011 12:14

AW: Mal wieder Threads
 
Und was ist das:
Zitat:

In der schleife (dem eigentlichen Thread) wird immer alle 100ms ausgegeben welches file er grade bearbeitet, wieviel es ingestamt sind und noch 2-3 ausgaben. Das mache ich nichtmehr in dem Thread mit z.b.

Delphi-Quellcode:
Form1.Label1.Caption:='doedel';


DelTurbo 5. Nov 2011 12:19

AW: Mal wieder Threads
 
Zitat:

Zitat von DelTurbo (Beitrag 1134578)
In der schleife (dem eigentlichen Thread) wird immer alle 100ms ausgegeben welches file er grade bearbeitet, wieviel es ingestamt sind und noch 2-3 ausgaben. Das mache ich nichtmehr in dem Thread mit z.b.

Form1.Label1.Caption:='doedel';

Sondern dafür habe ich eine extra routine die mit Postmessage aufgerufen wird.

Bitte lies dochmal richtig. Ich habe nun die sachen fett gemacht.

Bernhard Geyer 5. Nov 2011 12:21

AW: Mal wieder Threads
 
Wie läuft genau der DB-Zugriff. hast du für jede Thread auch eine eigene Connection? Ist die verwendete Zugriffskomponenten überhaupt Thread-Sicher?

Luckie 5. Nov 2011 12:24

AW: Mal wieder Threads
 
Versuch es mal mit SendMessage. Aber wenn du die Threadklasse benutzt würde ich es sicherheitshalber mit Synchronize machen. Und bitte wirf mir nicht vor, dass ich besser lesen solle, wenn du schon so sparsam mit Quellcode bist.

DelTurbo 5. Nov 2011 12:33

AW: Mal wieder Threads
 
Zitat:

Zitat von Luckie (Beitrag 1134592)
Und bitte wirf mir nicht vor, dass ich besser lesen solle, wenn du schon so sparsam mit Quellcode bist.

Das war doch kein vorwurf. Man(n) kann dochmal was überlesen. Das ist mir nun schon öfters hier passiert. "Ihr" lest sachen aus sätzen, die da garnicht stehen. Stimmt der Focus vom Röhrenmonitor nicht? Oder seit ihr wirklich sooo dünnhäutig??? Sorry aber das verstehe ich wirklich nicht. Da einen vorwurf rauszulesen.

Ich greife keinen an, beschimpfe keinen, und muss mich auchnoch für sachen rechtfertigen die ich garnicht gemacht habe. Irgendwie bleibt mir da die luft weg.

Medium 5. Nov 2011 12:34

AW: Mal wieder Threads
 
Wie versendest du denn Strings mit PostMessage?

Luckie 5. Nov 2011 12:36

AW: Mal wieder Threads
 
Sollte kein Problem sein, da ja alles im selben Prozess bleibt.

Medium 5. Nov 2011 12:38

AW: Mal wieder Threads
 
Wenn es ein Pointer auf einen lokalen String ist, wird's potenziell ekelig.

DelTurbo 5. Nov 2011 12:54

AW: Mal wieder Threads
 
Nein. Ich mache mir für sowas immer Records. Das erste ist ein InUse:Boolean. Ist der Record belegt, nehm ich den nächsten oder warte bis einer frei wird.

Da wo ich "reinposte" sieht der anfang immer so aus

Delphi-Quellcode:
procedure TReadDataFrm.RefreshRDObj(var Msg: TMessage);
var
   i      :Integer;
begin
      i := Integer(Msg.lParam);
da habe ich dann die nummer auf dem record, der "zu mir" gehört. Der Record ist Global und da stehen dann alle sachen drinne die ich in dem moment brauche. Strings,Integer usw..

Ich habe nun mal SendMessage genommen. Da der fehler nicht reproduzierbar ist, kann ich nur warten....

grl 5. Nov 2011 12:55

AW: Mal wieder Threads
 
Also, prinzipiell sollte man im Thread immer nur mit PostMessage arbeiten.

Mal so ganz ins blaue geraten: Du sendest den Text mit WM_COPYDATA - und das ist nicht Thread-geeignet.

Ein bisserl mehr Quellcode wäre nett, dann könnte man vielleicht auch eine gescheite Aussage treffen und dir leichter weiterhelfen. Mit der Kristallkugel ist's am Wochenende nix, da ist die konsequent auf Urlaub...

Gruß
Luggi

jaenicke 5. Nov 2011 13:05

AW: Mal wieder Threads
 
Zitat:

Zitat von Luckie (Beitrag 1134592)
Versuch es mal mit SendMessage. Aber wenn du die Threadklasse benutzt würde ich es sicherheitshalber mit Synchronize machen.

Das stört die Performance aber ggf. erheblich, je nach Anwendungsweise. Deshalb ist der Weg über PostMessage schon gut. Auch SendMessage stört die Performance, wenn auch nicht so sehr wie eine direkte Synchronisation.

Insofern ist PostMessage prinzipiell schon gut geeignet, aber eben nur, wenn es richtig gemacht wird. Wenn ich da aber schon etwas von globalen Records lese, schwant mir nichts Gutes. Wenn es ist wie ich vermute, wäre es kein Wunder, wenn SendMessage funktioniert... weil das schlicht wartet bis die Message abgearbeitet wurde und damit alles ggf. noch zur Verfügung steht.
Aber genau das möchte man ja bei Threadkommunikation vermeiden.

Aber wenn eben trotz mehrfacher Bitte (fast) kein Quelltext gepostet wird, kann auch niemand wirklich sinnvoll helfen... :roll:
Es geht ja nicht um den gesamten Projektquelltext oder so, sondern nur um das Gerüst wie die Threads und deren Kommunikation denn nun aussehen. Deshalb:
Zitat:

Zitat von grl (Beitrag 1134599)
Ein bisserl mehr Quellcode wäre nett, dann könnte man vielleicht auch eine gescheite Aussage treffen und dir leichter weiterhelfen. Mit der Kristallkugel ist's am Wochenende nix, da ist die konsequent auf Urlaub...

Full ack!

Sir Rufo 5. Nov 2011 13:10

AW: Mal wieder Threads
 
Zitat:

Zitat von DelTurbo (Beitrag 1134598)
Da habe ich dann die nummer auf dem record, der "zu mir" gehört. Der Record ist Global und da stehen dann alle sachen drinne die ich in dem moment brauche. Strings,Integer usw..

Hmmm, warum nimmst du keine TCollection und definierst dir ein passendes TCollectionItem dazu.
Von dem neuen TCollectionItem übergibst du per PostMessage oder SendMessage die ID (nicht den Index!) und schickst das auf die Reise. Der Empfänger kann nun aus dieser Collection sich das passende Item (mit der ID) herausnehmen und hat auch alle Informationen.

Generell würde ich auch die Jobs nicht als Thread definieren, sondern die Jobs durch einen WorkThread ausführen lassen.
Der WorkThread wird über einen WorkManager gestartet und dieser verwaltet passenderweise auch noch die Collection mit den Nachrichten.

Hier mal ein schnell hingetippeltes Projekt
Delphi-Quellcode:
type
IWorkManager = interface
procedure SendMessage(<ParameterListe anpassen>);
procedure PostMessage(<ParameterListe anpassen>);
end;

// Interface für den WorkJob
IWorkJob = interface
procedure SetWorkManager( aWorkManager : IWorkManager );
procedure DoExecute;
end;

TWorkThread = class( TThread )
private
  fWorkJob : IWorkJob;
protected
  procedure Execute; override;
public
  constructor Create( CreateSuspended : Booelan; aWorkJob : IWorkJob );
end;

TWorkManager = class( TInterfacedObject, IWorkManager )
public
  procedure AddJob( aWorkJob : IWorkJob );
end;

procedure TWorkManager.AddJob( aWorkJob : IWorkJob );
begin
  aWorkJob.SetWorkManager( Self );
  with TWorkThread.Create( True, aWorkJob ) do
  begin
    FreeOnTerminate := True;
    Resume;
  end;
end;
Es gibt auch noch diese Bei Google suchenOmniThreadLibrary die sowas schon direkt alles mitbringt (glaube ich).
Sowas baue ich aber lieber selber :)

Furtbichler 5. Nov 2011 13:18

AW: Mal wieder Threads
 
Also ich kapsle einen String in einer Klasse. Das ist bestimmt oversized, aber bisher hatte ich damit keine Probleme...
(Das hier ist allerdings aus dem Gedächtnis)
Delphi-Quellcode:
Type
  TStringContainer = Class
  Public
     MessageString : String;
     Constructor Create (aMessage : String);
  End;

Constructor TStringContainer.Create (aMessage : String);
Begin
  MessageString := aMessage
End;

...
Procedure TMyThread.SendAString (AString : String);
Begin
  PostMessage(MainHandle, WM_STRING, Integer(TSTringContainer.Create(aString)),0);
End;

...
Procedure TMainTask.ReceivStringMessageHandler (Var Msg : TMessage);
Begin
  DoSomethingWith(TStringContainer(Msg.wParam).MessageString);
  TStringContainer(Msg.wParam).Free
End;
Is das ok so?

Nachtrag: Da mir das mit der Referenzzählung bei Strings nicht geheuer ist, mache ich das so.


@Sir Rufo: Threads mit FreeOnTerminate habe ich mir abgewöhnt, denn wenn ich die Anwendung beende und der Thread noch im Speicher rumfleucht, bekomme ich jedesmal eine schöne Exception, denn der Code zum Terminieren eines Threads baut darauf auf, das die Classes.pas noch nicht ihren finalize-Teil durchlaufen hat.

DelTurbo 5. Nov 2011 13:25

AW: Mal wieder Threads
 
Da ich wirklich nicht alle posten kann, wäre einfach zu lang, habe ich mal die wichtigen sachen zusammen gestellt. Wenn ich was vergessen habe, dann beschimpft einfach :-D

Delphi-Quellcode:
type
  TReadDataFrm = class(TForm)
    RzPanel1: TRzPanel;
    StatusBox: TRzGroupBox;
[SNIP]
  private
    { Private-Deklarationen }
    procedure RefreshRDObj(var Msg: TMessage); message Refresh_RDObj;
  public
    { Public-Deklarationen }
  end;

procedure TReadDataFrm.RefreshRDObj(var Msg: TMessage);
var
   i      :Integer;
begin
    i := Integer(Msg.lParam);
[SNIP]
    MyThread.InUse:=False;
end; {RefreshRDObj(var Msg: TMessage)}
Das hier ist dann im Thread der eigentliche aufruf. Er achtet noch auf InUse da es vorher ja mit Postmessage gemacht wurde.

Delphi-Quellcode:
      if AppRun=1 then begin
        AppRun:=0;
        if NOT MyThread.InUse then begin
          MyThread.i:=2;
          MyThread.InUse:=True;
          SendMessage(MyThread.WinHandle, Refresh_RDObj, 0, MyThread.i);
        end;
      end;
Apprun ist auch Global. Es wird alle 100ms auf 1 gesetzt, über einen normalen TTimer. Da grade dieses nicht mehrmals aufgerufen wird, ist das kein record-array.

Das teil sieht so aus.

Delphi-Quellcode:
type
  TMyThread = record
      InUse               :Boolean;
      RunType            :Integer;
    PathCount    :Integer;
    FileCount    :Integer;
    SizeCount    :Int64;
      FileName         :String;
    WinHandle       :THandle;
[SNIP]
     AktDirVar    :String;
     AktProgress  :Integer;
      i                     :Integer;
      Str                  :String;
end;
Winhandle wird vor dem start des Thread gesetzt. Wie gesagt, das ist kein "eigener" Thread wie ich ihn im ersten post hier beschrieben habe, sondern ein TJvMTThread. Damit habe ich noch nie was gemacht. Alle meine progs liefen immer mit Thread wie im 1. post beschrieben. Vielleicht vergesse ich da was?!?

So, nun hab ich sooo lange gesucht und Copy&Pastet das ne Rote Box kam...

[Nachtrag]
Mit der Variante aus dem ersten post, habe ich ein prg gemacht was bis zu 200 threads zeitgleich laufen hat. Das klappt einwandfrei. Eventuell sollte ich vom TJvMTThread wieder weggehen und es so machen wie ich es gewohnt bin.

Bernhard Geyer 5. Nov 2011 13:38

AW: Mal wieder Threads
 
Zitat:

Zitat von grl (Beitrag 1134599)
Mal so ganz ins blaue geraten: Du sendest den Text mit WM_COPYDATA - und das ist nicht Thread-geeignet.

WM_COPYDATA ist überhaupt nicht geeignet im eigenen Prozess Infos zu verteilen. Diverse Anwendungen wie nView konsumieren solche Meldungen teilweise selbst, sprich die Message kommt nicht an.

jaenicke 5. Nov 2011 14:30

AW: Mal wieder Threads
 
Zitat:

Zitat von Sir Rufo (Beitrag 1134601)
Delphi-Quellcode:
  with TWorkThread.Create( True, aWorkJob ) do
  begin
    FreeOnTerminate := True;
    Resume;
  end;

:firejump:
Ein Spiel mit dem Feuer. Mit Glück geht sowas gut, aber will man sich darauf verlassen? Nicht umsonst ist Resume mittlerweile als deprecated gekennzeichnet. Zitat aus der Hilfe:
Zitat:

Warnung: Die Methoden Resume und Suspend sollten nur für das Debuggen verwendet werden.
Hintergrund unter anderem:
Wenn der Thread zu schnell fertig ist bevor Resume beendet ist, zieht das FreeOnTerminate dem Code den Boden unter den Füßen weg. Und wenn es nur passiert, weil im Thread eine Exception auftritt, ausschließen kann man so etwas jedenfalls kaum. Dazu gibt es auch umfangreiche Diskussionen, unter anderem auch im Embarcadero Forum unter Beteiligung von deren Entwicklern. Das Fazit ist überall das gleiche: Nie Resume verwenden ist das beste.

Deshalb rate ich stattdessen dringend zu einer sauberen Lösung. Insbesondere hier im Beispiel ist das ja denkbar einfach: Einfach den Thread nicht suspended starten...
Zitat:

Zitat von DelTurbo (Beitrag 1134603)
Apprun ist auch Global. Es wird alle 100ms auf 1 gesetzt, über einen normalen TTimer.

Ich frage mich die ganze Zeit wozu das ganze eigentlich global ist. Du kannst dir doch Speicher reservieren, per Message an deinen Hauptthread schicken und der gibt den wieder frei. Dann kannst du dir die ganze zusätzliche Synchronisation sparen.

Und das mit dem Timer kannst du dir dann auch sparen. Denn der Thread kann sich einfach kurz mit Sleep schlafen legen und weitermachen.

Ansonsten gibt es auch noch Events (CreateEvent, SetEvent, ...) um die Signale hin- und herzuschicken. Die sind auch threadsicher.

Zitat:

Zitat von DelTurbo (Beitrag 1134603)
Mit der Variante aus dem ersten post, habe ich ein prg gemacht was bis zu 200 threads zeitgleich laufen hat.

Wobei so viele Threads das ganze natürlich sehr stark ausbremsen, wenn die wirklich zeitgleich arbeiten und nicht größtenteils schlafen.

DelTurbo 5. Nov 2011 14:52

AW: Mal wieder Threads
 
Hi,
also ich weiss nun nicht ob das mit AppRun so eine grosse rolle spielt. Ich habe es einfach in der "unit1" deklariert und fertig. Was soll ich für (theoretisch einem Byte) speicher "hohlen". Find ich bissl umständlich.

Zum Thread. Der soll nicht schlafen, der soll arbeiten. Den gedanken gang kann ich leider nicht nachvollziehen. Ich habe das nun endlich so schnell, das ich mit bis zu 150MBit (im GBitLan) den MySqlServer "anblasen" kann. Und dann soll ich ein sleep einbauen? Sorry, das verstehe ich auch nicht.

Zu den 200 Threads. Das war einmal ein Peak der erreicht wurde. Natürlich Rendern die keine Filme. Normal sind ca. 30-50 Threads, wovon bis zu 10 zeitgleich laufen können (kommt drauf an was er macht). Und selbst die, die "laufen" warten meistens nur rum bis der FTP-Server antwortet.

Danke an alle....

Furtbichler 5. Nov 2011 18:06

AW: Mal wieder Threads
 
Zitat:

Zitat von jaenicke (Beitrag 1134610)
Deshalb rate ich stattdessen dringend zu einer sauberen Lösung. ... Einfach den Thread nicht suspended starten...

Oder FreeOnTerminate nicht verwenden.

jaenicke 5. Nov 2011 18:26

AW: Mal wieder Threads
 
Zitat:

Zitat von DelTurbo (Beitrag 1134614)
Zum Thread. Der soll nicht schlafen, der soll arbeiten. Den gedanken gang kann ich leider nicht nachvollziehen. Ich habe das nun endlich so schnell, das ich mit bis zu 150MBit (im GBitLan) den MySqlServer "anblasen" kann.

Naja, ich hatte das so verstanden, dass dein Timer den Thread anstößt und der daraufhin Daten in einem globalen Objekt/Record zur Verfügung stellt und wiederum über ein globales Flag signalisiert, dass er fertig ist.

DelTurbo 6. Nov 2011 10:53

AW: Mal wieder Threads
 
Nein, ich nehme mal die schuld auf mich damit keine weiteren diskusionen aufkommen. Das hauptprob ist ja, das ich schlecht die komplette source hier posten kann. Ich denke mal das würde den Thread sprengen, und nur mehr arbeit machen. Deswegen hatte ich versucht nur die hauptsächlichen sachen zu posten. Ich finde sowas relativ schwer, weil man was vergisst oder weglässt, weil ich selber es ja weiss.

Der Thread ist im grunde eine schleife die "vollgas" einen MySqlServer fillt (mit DirectMysql). Es war schon schwer genug, da einen guten speed zu bekommen. Deswegen der externe timer. Der (Apprun) wird in der schleife abgefragt. Hat er zugeschlagen gebe ich die infos aus. Damit man(n) nicht doof auf eine "Bitte warten" box schauen muss, sondern sieht wo er grade ist.

Allerdings muss ich sagen, seitdem ich Send statt Postmessage nutze, knallt es nichtmehr. Warum das so ist, weiss ich nicht. Zeitlich ist der unterschied nicht messbar.

Ich hatte in der abfrage extra noch "aufgepasst" das Postmessage wirklich zuende ist bevor ich sachen ändere und wieder ein Post schicke. Das habe ich extra gepostet. Daran hatte ich gedacht ^^

sx2008 6. Nov 2011 11:18

AW: Mal wieder Threads
 
Also bei Threads halte ich mich immer an folgende Regeln:
1.) keine Windows-API Funktionen (z.B. BeginThread()) verwenden, sondern immer nur von der TThread-Klasse ableiten.
Der direkte Aufruf von Windows-API Funktionen ist hier viel zu gefährlich und fehlerträchtig.
Warum sich unnötigerweise in Gefahr begeben nur um einige Bytes und Microsekunden zu sparen?

2.) falls viele kleine Aufgaben zu erledigen sind, sollte man einen Threadpool in Betracht ziehen

3.) ein Thread sollte möglichst selbstständig und ohne Kontakt zu anderen Threads ablaufen.
Das bedeutet insbesondere: nicht auf globale Variablen zugreifen (ausser es geht nicht anderst).
Natürlich auch keine Funktionen aufrufen, die mit globalen Daten arbeiten.
Das Thread-Objekt bekommt alle nötigen Daten von Aussen über Properties übergeben und arbeitet dann mit seiner lokalen Kopie.
Die Ergebnisse des Threads werden über Properties zurückgegeben.
Man könnte die Thread-Klasse also unverändert ausschneiden und in ein anderes Programm einfügen, weil sämtliche Abhängigkeiten über Properties der Klasse bedient werden.
Das Prinzip ist EVA: Eingabe - Verarbeitung - Ausgabe

4.) Kommunikation mit der VCL vermeiden bzw. so gering wie möglich halten

5.) Innerhalb der Execute-Methode sollte man immer wieder das Property Terminated abfragen (Falls True, Thread sofort beenden)
Fragt man Terminated zu häufig ab, bremst das den Thread, fragt man zu selten oder gar nicht ab, behindert das das Verhalten (z.B. beim Herunterfahren von Windows).

6.) Exceptions innerhalb des Threads abfangen (andernfalls gehen sie verloren)
Delphi-Quellcode:
procedure TMyThread.Execute;
begin
  try
    InternalExecute;
    ReturnValue := 0;
  except
    on E:Exception do
    begin
      OutputDebugString(PChar(E.Message));
      ReturnValue := -1;
      self.ExceptMessage := E.Message; // Meldung für später in einem Property merken
    end;
end;
Besonders Punkt 3. ist in der Praxis nicht so einfach und kann auch je nach Aufgabe nicht immer so erfolgen.
Aber die Probleme werden merklich reduziert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:43 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