Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Thread Terminate nicht aufrufbar
whitef - Sa 25.08.12 01:32
Titel: Thread Terminate nicht aufrufbar
hi,
hab da noch eine Frage zum Thread.
Es klappt alles soweit, bis auf das
Terminate aus einer anderen Unit.
Ich hab über Delphi eine neue Unit (Klasse TThread) angelegt. Ich habe den Namen "MyThread" vergeben.
Das kam in der neuen Unit raus
Delphi-Quelltext
1: 2:
| type MyThread = class(TThread) |
Jetzt möchte ich gerne in Unit1 auf meiner Form1 mittels button OnClick > MyThread.Terminate; ausführen um es in der Threadschleife abfragen zu können.
Deswegen habe ich in meiner neuen "Thread"-Unit namens "UnitMyThread" folgendes geändert:
Delphi-Quelltext
1: 2:
| type TMyThread = class(TThread) |
und das hinzugefügt ("UnitMyThread"):
Delphi-Quelltext
1: 2:
| public MyThread : TMyThread; |
Das hier habe ich noch in "Unit1" hinzugefügt:
Delphi-Quelltext
1: 2: 3: 4: 5:
| ... implementation
uses UnitMyThread; ... |
Jetzt kann ich zwar in der "UnitMyThread"
MyThread.Terminate; ausführen, aber ich möchte es ja von Unit1 aus ausführen.
Was hab ich den jetzt vergessen?
PS: Habt Nachsicht, schaut auf die Uhrzeit des Postings :-D
jaenicke - Sa 25.08.12 07:23
Wegen deines anderen Threads:
Vorsicht, wenn du noch FreeOnTerminate nutzt. Dann solltest du keinerlei Referenz auf den Thread behalten. Wenn der Thread sich selbst verwaltet, darfst du auch nicht versuchen auf das Threadobjekt zuzugreifen. Denn du weißt ja nie wann es weg ist.
Einzige Alternative, wenn du auf das Threadobjekt zugreifen willst:
Benutze nicht FreeOnTerminate, sondern gib den Thread auch manuell von außen frei nachdem er beendet wurde (WaitFor).
Zum Problem:
Unter public kannst du nur aus dem Objekt heraus zugreife, schreibe es stattdessen in eine Klassenvariable, dann kannst du von außen zugreifen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| public class var MyThread: TMyThread;
...
TMyThread.MyThread.Terminate; |
whitef - Sa 25.08.12 09:25
Vielen Dank, nun kann ich auf Form1
TMyThread.MyThread.Terminate; aufrufen.
Aber da taucht das nächste Problem auf, ein
EAccessViolation wird ausgelöst sofern man obigen Befehl ausführt:
Form1:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm1.Button1Click(Sender: TObject); begin if TMyThread.MyThread.ThreadRunning then begin TMyThread.MyThread.Terminate; showmessage('terminiert'); end else showmessage('Zzt. kein thread läuft'); end; |
UnitMyThread:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function TMyThread.ThreadRunning:boolean; begin result:=running>0; end;
procedure TMyThread.Execute; var i : Integer; begin inc(running); Synchronize(Sync_Panels); for i := 0 to (StrToInt(varThreadDateien) - 1) do begin if not Terminated then begin ... end else break; end; dec(running); end; |
Button1Click:
Quelltext
1:
| ...EAccessViolation... |
jfheins - Sa 25.08.12 09:32
Also sofern das jetzt nicht bewusst als Singleton geplant ist würde ich auf die Klassenvariable verzichten.
Lege dir stattdessen ein privates Feld im Formular an. Also bei der Definition von Form1 sowas wie
Delphi-Quelltext
1: 2:
| private MyThread: TMyThread; |
Und dann beim Erstellen des Threads:
Delphi-Quelltext
1:
| MyThread := TMyThread.Create(..., ...); |
(Die Variable Thread von vorher war ja lokal, da du jetzt von woanders drauf zugreifen möchtest, musst du sie im Scope "hoch stufen")
Und dann, wie gesagt, nicht FreeOnTerminate verwenden.
whitef - Sa 25.08.12 09:42
zum testen, ist alles in meinem aktuellen Projekt, später werde ich diese Thread Unit wieder soweit clearen, dass ich dass Grundgerüst bei anderen Projekten mitübernehmen kann.
Also ich will diesen Thread in eine extra Unit auslagern und nicht im Form1 deklarieren. Nur von Form1 aus aufrufen und beenden.
jfheins - Sa 25.08.12 10:03
Um das deklarieren einer Variable wirst du nicht herum kommen 8)
Im Gegenteil, siehe dein eigener Code:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm1.btSaveClick(Sender: TObject); var i: Integer; TargetDir, datei0, datei1, dateien: String; Thread: TMyThread; begin |
Und jetzt verschiebst du einfach diese Deklaration in den private-Teil deines Formulars. Dann kannst du nämlich auch aus anderen Funktionen darauf zugreifen.
Also das deklarieren ist volkommen OOP konform und widerspricht nicht der Kapselung ;)
whitef - Sa 25.08.12 10:37
Danke!
Form1:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| ... uses ..., UnitMyThread; ... public MyThread: TMyThread;
implementation
procedure TForm1.btAbbrechenClick(Sender: TObject); begin MyThread := TMyThread.Create(..., ...); end;
procedure TForm1.Button1Click(Sender: TObject); begin if MyThread.ThreadRunning then begin MyThread.Terminate; showmessage('terminiert'); end else showmessage('Zzt. läuft kein thread'); end; |
UnitMyThread:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function TMyThread.ThreadRunning:boolean; begin result:=running>0; end;
procedure TMyThread.Execute; var i : Integer; begin inc(running); Synchronize(Sync_Panels); for i := 0 to (StrToInt(varThreadDateien) - 1) do begin if not Terminated then begin ... end else break; end; dec(running); end; |
jfheins - Sa 25.08.12 10:47
Okay, weitere Fragen:
1. Hast du das FreeOnterminate := true; entfernt?
2. Klickst du auch brav auf den Button "btAbbrechen" bevor du auf den Button "Button1" klickst?
3. Wenn's immer noch Probleme gibt, zeige bitte etwas mehr Code.
MfG
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!