Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi XE4 Probleme mit Thread.Start (anstatt Resume) (https://www.delphipraxis.net/175492-xe4-probleme-mit-thread-start-anstatt-resume.html)

Alex_ITA01 25. Jun 2013 20:27

XE4 Probleme mit Thread.Start (anstatt Resume)
 
Hallo zusammen,
ich habe seit heute XE4 Pro und habe meine Anwendung von Delphi 2009 übernommen. Ein paar Anpassungen musste ich machen aber es lässt sich alles compilieren und ich habe auch keine Warnungen oder Fehler.

Leider bin ich darauf gestoßen, dass ich .Resume von einem Thread nicht mehr verwenden soll, da es veraltet ist.
Jetzt nehme ich eben das besagte .Start und siehe da, ich bekomme AV. Exception EThread, ein bereits laufender Thread kann nicht gestartet werden (oder so ähnlich, habe den genauen Text jetzt nicht vor Augen).
Das komische ist aber, dass ich ein paar Zeilen oben drüber den Thread mit .Create(True) erzeuge und dann setze ich paar Variablen vom Thread und ich frage sogar ab "if MyThread.Suspended then MyThread.Start".
Suspended liefert mir True und nach dem Aufruf von Start bekomme ich eine Exception.

Hat jemand eine Idee was das sein könnte (auch wenn ich grad kein Source zur Hand habe)?

PS: Wenn ich das .Start wieder auf .Resume ändere, geht es ohne Probleme.
Ich habe auch festgestellt, wenn ich alle meine .Resume Aufrufe in .Start ändere und den besagten Exception Typ ignoriere, dann startet meine Anwendung gar nicht und ich sehe sie nur im TaskManager mit 0% CPU Auslastung und 21MB Speicher Verbrauch.

Nutze Win8, 64bit -> Anwendung als 32bit compiliert.

Gruß
Alex

jaenicke 25. Jun 2013 21:19

AW: XE4 Probleme mit Thread.Start (anstatt Resume)
 
Starte deine Threads nur Suspended, wenn das absolut erforderlich ist. In 99,9% der Fälle ist es das nicht.

In den meisten Fällen passiert das nur, weil die Parameter nicht wie es am sinnvollsten ist einem eigenen Konstruktor des Threads übergeben werden, sondern erst danach gesetzt werden...

Alex_ITA01 26. Jun 2013 08:21

AW: XE4 Probleme mit Thread.Start (anstatt Resume)
 
So, habe es gelöst und meines Erachtens nach ein Fehler im TThread gefunden.

Delphi-Quellcode:
Constructor TMyThread.Create;
begin
  inherited Create(True);

  //hier noch paar Stringlisten oder ähnliches erstellen, welche im Execute vom Thread benutzt werden (deswegen mit Parameter True erstellt!)

  Start;
end;
Der Fehler entsteht folgender Maßen:

Das .Start im Constructor vom Thread nach dem Initialisieren von bestimmten Variablen ruft intern "InternalStart(False);" auf. Dies sieht wie folgt aus:

Delphi-Quellcode:
procedure TThread.InternalStart(Force: Boolean);
begin
  if (FCreateSuspended or Force) and not FFinished and not FExternalThread then
  begin
    FSuspended := False;
    FCreateSuspended := False;
{$IF Defined(MSWINDOWS)}
    if ResumeThread(FHandle) <> 1 then
      raise EThread.Create(SThreadStartError);
{$ELSEIF Defined(MACOS)}
    pthread_mutex_unlock(FCreateSuspendedMutex);
{$ELSEIF Defined(LINUX)}
    sem_post(FCreateSuspendSem);
{$ENDIF LINUX}
  end else
    raise EThread.Create(SThreadStartError);
end;
Damit wird FSuspended und FCreateSuspended zurückgesetzt (warum wird hier FCreateSuspended zurückgesetzt???).

Nach dem End; vom Constructor-Ende wird aber noch "AfterConstruction" aufgerufen.
Das sieht wie folgt aus:

Delphi-Quellcode:
procedure TThread.AfterConstruction;
begin
  if not FCreateSuspended and not FExternalThread then
    InternalStart(True);
end;
Damit wird InternalStart wieder aufgerufen mit Übergabe = True (Force). Da Force = True ist, kommt er in InternalStart auch wieder in das "ResumeThread <> 1" rein und macht sich ins Hemd, da der Thread ja bereits läuft (durch mein Aufruf von .Start).

Meines Erachtens nach dürfte doch das FCreateSuspended gar nicht zurückgesetzt werden. Die Variable soll doch dafür sein, um den Zustand zu erkennen, wie der Thread erstellt wurde! Wenn diese Variable nämlich nicht zurückgesetzt wird, würde es gehen, da "AfterConstruction" dann das "InternalStart(True)" nicht nochmal aufruft.

Bug? Absicht? Keine Ahnung.

Habe das ".Start" aus dem Constructor raus genommen und nach dem erstellen des Threads aufgerufen, dann gehts.

Hoffe damit auch den anderen suchenden geholfen zu haben.

Wenn hierzu jemand noch gerne was sagen möchte, würde ich mich freuen ;-)

Grüße
Alex

jfheins 26. Jun 2013 08:34

AW: XE4 Probleme mit Thread.Start (anstatt Resume)
 
Du könntest auch das starten komplett automatisch machen lassen: Einfach dem ursprünglichen Constructor false übergeben. Dein Konstruktor wird ja trotzdem vollständig ausgeführt, bevor (im AfterConstruction()) der Thread tatsächlich gestartet wird.

Nach dieser Antwort: http://stackoverflow.com/a/6762791 ist es schlichtweg ein Fehler, Start() im Konstruktor eines Threads aufzurufen.

Alex_ITA01 26. Jun 2013 09:05

AW: XE4 Probleme mit Thread.Start (anstatt Resume)
 
Wenn man das vorher gelesen oder gefunden hätte, wäre die Fehlersuche schneller gegangen.
Sowas darf aber auch gerne in der Hilfe stehen, denke ich ;-)

Zacherl 27. Jun 2013 14:35

AW: XE4 Probleme mit Thread.Start (anstatt Resume)
 
Kleine Anmerkung noch: Suspend() ist nicht umsonst deprecated. Threads zu suspendieren ist immer schlecht. Erstelle dir lieber ein Event mit MSDN-Library durchsuchenCreateEvent, dann kannst du deinen Thread per MSDN-Library durchsuchenWaitForSingleObject schlafen lassen, bis du das Event per MSDN-Library durchsuchenSetEvent aktivierst. Über MSDN-Library durchsuchenResetEvent kannst du es wieder entsprechend deaktivieren.


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