Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Thread Execute wird nicht ausgeführt wenn constructor


whitef - Fr 24.08.12 18:07
Titel: Thread Execute wird nicht ausgeführt wenn constructor
hi,
ich habe ein Thread in meinem Projekt eingebaut.
Dieses mal wollte ich aber ein paar Werte von Beginn von meiner Form an dem Thread zukommen lassen, demnach mit constructor Create.

Leider kommt es mir nun so vor dass constructor TMyThread.Create zwar ausgeführt wird, aber nicht mehr procedure TMyThread.Execute;.

Ist das normal?

Falls nicht, hier mein Projekt:

Unit meiner Form (verkürzt):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
...

implementation

uses UnitMyThread;

...

procedure TForm1.btSaveClick(Sender: TObject);
var i: Integer; TargetDir, datei0, datei1, dateien: String; Thread: TMyThread;
begin
....
for i := 0 to (StrToInt(dateien) - 1do begin
...
datei0 := Form1.lblPfadSource.Caption + Form1.FileListBox.Items[i];
datei1 := TargetDir + Form1.FileListBox.Items[i];

Thread := TMyThread.Create(datei0, datei1);
end;
end;


Unit des Threads (komplett):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
unit UnitMyThread;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, JPEG;

type
  TMyThread = class(TThread)

  protected
     datei00        : String;
     datei11        : String;

    procedure Execute; override;

  Public
    constructor Create( datei0:String; datei1:String );
  Private

  end;

implementation

constructor TMyThread.Create( datei0:String; datei1:String );
Begin
inherited Create(true);
  datei00        := datei0;
  datei11        := datei1;
  showmessage('cre: ' + datei00);                   /////////////////// Wird angezeigt
FreeOnTerminate:=True;
End;

procedure TMyThread.Execute;
begin
  showmessage('exe: ' + datei00);                  /////////////////// Wird NICHT angezeigt
  CopyFile(PChar(datei00), PChar(datei11), True);
end;

end.


jfheins - Fr 24.08.12 18:18

Also erstmal ist ein showmessage in dem Thread eine eher schlechte Idee.
Zum eigentlichen Problem:inherited Create(true);
Der Parameter des originalen Konstruktors heißt "CreateSuspended" - nur so zum denken :P


whitef - Fr 24.08.12 18:46

Das mit "showmessage" hab ich schonmal gesagt bekommen, dass das nix in einem thread zu suchen hat; ist ja nur testweise drin.

Nur leider kann ich mit dem Rest was du geschrieben hast, nichts anfangen - ich kann mir ja nichts ausdenken...
Muss ich den originalen Parameter nehmen? Kann ich dann weitere Parameter hinzufügen? Falls nein, wie übernehme ich dann weitere Parameter in mein Thread...

Die Frage ist also noch offen


Sinspin - Fr 24.08.12 21:01

Was bezweckst Du mit inherited Create(true);? Wenn Du mal in die Hilfe schaust was Du da mit true anstellst bist Du, denke ich, ein ganzes Stück schlauer.
Das da inherited ... aufgerufen werden muss sollte außer frage stehen.
Also, was bedeutet der Parameter "CreateSuspended" den Du da mit true angibst?

Dein Quelltext ist erhlich gesagt nicht sonderlich glücklich formatiert *Arme hochreiß, wegrenn*. Tschuldigung.
Zudem nochmal: Jegliche Aufrufe von irgendwelchen Dialogen, Formularen oder Zugriffe auf Formulare haben in einem Thread nichts zu suchen. Das da nichts angezeigt wird ist noch der glückliche Verlauf. Damit kannst Du auch Dein Programm abschießen.
Zu diesem Punkt auch Hilfe lesen: Procedure Synchronize.


whitef - Fr 24.08.12 22:24

Für alle Suchenden, die nicht in der Hilfe schauen möchten und sich diese Zeit bei dieser Hitze sparen möchten:



Delphi-Quelltext
1:
inherited Create(CreateSuspended(FALSE));                    

...bewirkt den weiteren Ablauf des Threads, demnach wird automatisch die prozedur TMyThread.Execute angestoßen.
*ungetestet



Delphi-Quelltext
1:
inherited Create(CreateSuspended(TRUE));                    

bewirkt den temporären Stop des Threads, demnach müsste man in der selben prozedure folgendes hinzufügen, damit die prozedur TMyThread.Execute angestoßen wird "Thread.Resume".
*ungetestet



Unit des Threads (komplett):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
unit UnitMyThread;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, JPEG;

type
  TMyThread = class(TThread)

  protected
     datei00        : String;
     datei11        : String;

    procedure Execute; override;

  Public
    constructor Create( datei0:String; datei1:String );
  Private

  end;

implementation

constructor TMyThread.Create( datei0:String; datei1:String );
Begin
inherited Create(CreateSuspended(FALSE));           /////////////////// Hier sind die Änderungen
  datei00        := datei0;
  datei11        := datei1;
  showmessage('cre: ' + datei00);
FreeOnTerminate:=True;
End;

procedure TMyThread.Execute;
begin
  showmessage('exe: ' + datei00);
  CopyFile(PChar(datei00), PChar(datei11), True);
end;

end.


jfheins - Fr 24.08.12 23:15

Also hast du die Hilfe bedient und etwas gelernt :)

Zur Vollständigkeit halber: das "CreateSuspended" ist eigentlich noch zuviel, es müsste

Delphi-Quelltext
1:
inherited Create(false);                    

sein. Das andere dürfte eigentlich nicht kompilieren !?

Uns in späteren Versionen von Delphi doll man nicht mehr Thread.Resume benutzen,
sondern (falls der Thread schlafend erzeugt wird) mit TThread.Start(); starten.


jaenicke - Sa 25.08.12 07:17

FreeOnTerminate + Resume = böse
Grund: Der Thread könnte, wenn er zu wenig zu tun hat, schon vor dem Aufruf von Resume freigegeben sein... --> Race Condition

Deshalb am besten den Thread gar nicht erst Suspended erzeugen, wenn man FreeOnTerminate nutzt.