Autor |
Beitrag |
Xearox
Beiträge: 260
Erhaltene Danke: 3
|
Verfasst: Fr 13.02.15 09:42
Hallo Zusammen,
dank Nersgatt konnte ich den Fehler in meinem vorheigen Thread relativ schnell finden =)
Nun habe ich ein paar Zeilen Code hinzugefügt und stehe erneut vor einem Problem.
Und zwar erstelle ich zur Laufzeit eine TTimer Komponente, diese wird erstellt, sobald der Thread gestartet wird.
Anschließend synce ich das ganze, doch die Caption vom Label steht weiter hin bei "0".
Packe ich nun im MyTimerEvent ein ShowMessage('Test'); rein, wird jede Sekunde einmal die Message aufgerufen und auch die Caption zählt langsam hoch, sobald ich aber die Message schließe, werden entsprechend alle Threads geschlossen und der Timer wird angehalten.
Gibt es da irgendwas, was ich übersehen habe? Weil, soviel ich jetzt heraus gelesen habe, läuft der Thread solange weiter, bis dieser abgeschlossen ist, oder nicht? Und da dort ein TTimer drin ist und dieser schließlich unendlich weiter läuft, bis ich den Timer deaktiviere, sollte doch der Thread auch weiter laufen, oder nicht?
Hier mal meinen Code, die Thread Blöcke sind entsprechend markiert.
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: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Label1: TLabel; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private public end;
TMeinThread1 = class(TThread) protected procedure Ausgabe; procedure Execute; override; end;
TMeinThread2 = class(TThread) protected procedure Ausgabe; procedure Execute; override; public procedure MyTimerEvent(Sender: TObject); end;
var Form1: TForm1;
implementation
{$R *.dfm} var Z: Integer;
procedure TMeinThread1.Ausgabe; begin Form1.Memo1.Lines.Add('Text'); end;
procedure TMeinThread1.Execute; begin Synchronize(Ausgabe); end;
procedure TMeinThread2.Ausgabe; begin Form1.Label1.Caption := IntToStr(Z); end;
procedure TMeinThread2.Execute; var MyTimer : TTimer; begin MyTimer := TTimer.Create(nil); MyTimer.Interval := 1000; MyTimer.OnTimer := MyTimerEvent; MyTimer.Enabled := true; Synchronize(Ausgabe); end;
procedure TMeinThread2.MyTimerEvent(Sender: TObject); begin Z := Z + 1; end;
procedure TForm1.Button1Click(Sender: TObject); var aThread : TMeinThread1; bThread : TMeinThread2; begin aThread := TMeinThread1.Create(false); bThread := TMeinThread2.Create(false); end;
procedure TForm1.FormCreate(Sender: TObject); begin Z := 0; end;
end. |
Ich habe die beiden ShowMessages jeweils auskommentiert, denn sobald diese wieder drin sind, funktioniert das ja, mit dem hochzählen.
Liebe Grüße und danke =)
|
|
Nersgatt
Beiträge: 1581
Erhaltene Danke: 279
Delphi 10 Seattle Prof.
|
Verfasst: Fr 13.02.15 09:51
Ok, hier wird es etwas umfangreicher.
Das Problem ist, dass Du Deinen Thread nur einmal durchlaufen lässt und er sich dann beendet. Also gibt er einmal Z aus und beendet sich dann. Da zu dem Zeitpunkt aber der Timer noch nie ausgelöst hat, ist Z noch 0.
Du solltest aber auf den Timer im Thread verzichten. Ich denke, Deine Intention ist es, im Label Sekundenweise hochzuzählen?
Das würde ich ungefähr so lösen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TMeinThread2.Execute; begin while not terminated do begin z := z + 1; Synchronize(Ausgabe); Sleep(1000); /* Sleep wirkt sich hier nur auf den Thread aus, die Anwendung selbst läuft weiter */ end; end; |
Den ganzen Krams mit dem Timer kannst Du Dir hier schenken.
Da der Thread nun in einer Schleife läuft, läuft der Thread nebenbei solange, bis er beendet wird (dabei wird von außen "Terminated" auf True gesetzt, durch Aufruf von bThread.Terminate.
_________________ Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
|
|
Xearox
Beiträge: 260
Erhaltene Danke: 3
|
Verfasst: Fr 13.02.15 10:29
Nersgatt hat folgendes geschrieben : | Ok, hier wird es etwas umfangreicher.
Das Problem ist, dass Du Deinen Thread nur einmal durchlaufen lässt und er sich dann beendet. Also gibt er einmal Z aus und beendet sich dann. Da zu dem Zeitpunkt aber der Timer noch nie ausgelöst hat, ist Z noch 0.
Du solltest aber auf den Timer im Thread verzichten. Ich denke, Deine Intention ist es, im Label Sekundenweise hochzuzählen?
Das würde ich ungefähr so lösen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TMeinThread2.Execute; begin while not terminated do begin z := z + 1; Synchronize(Ausgabe); Sleep(1000); /* Sleep wirkt sich hier nur auf den Thread aus, die Anwendung selbst läuft weiter */ end; end; |
Den ganzen Krams mit dem Timer kannst Du Dir hier schenken.
Da der Thread nun in einer Schleife läuft, läuft der Thread nebenbei solange, bis er beendet wird (dabei wird von außen "Terminated" auf True gesetzt, durch Aufruf von bThread.Terminate. |
Soweit so gut =) Das funktioniert nun super. Nur das mit dem Terminate klappt nicht so wirklich.
So wie ich das in den ganzen Tutorials und Beispielen Verstanden habe und wie du auch selbst geschrieben hast, wird der Thread erst beendet, wenn Terminated auf true gesetzt wird.
Wenn ich nun das ganze über einen zweiten Button zu lösen, erhalte ich allerdings die Fehlermeldung
Quelltext 1:
| Erste Gelegenheit für Exception bei $76DBC42D. Exception-Klasse EThread mit Meldung 'Ein extern erstellter Thread kann nicht beendet werden'. Prozess Project1.exe (6852) |
Code für Button 2
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.Button2Click(Sender: TObject); var bThread : TMeinThread2; begin bThread.Terminate; end; |
Muss ich das ganze innerhalb des Threads aufrufen? Wenn ja, wie kann ich dann mit dem zweiten Button arbeiten?
Mache ich nun stattdessen bThread.Terminated := true; erhalte ich vom Compiler die Meldung [DCC Fehler] Unit1.pas(103): E2129 Einer Nur-Lesen Eigenschaft kann kein Wert zugewiesen werden
Würde ich das mit einem Timer machen, hätte ich einfach über den zweiten Button, den time auf Timer.Enabled := false gesetzt.
|
|
Nersgatt
Beiträge: 1581
Erhaltene Danke: 279
Delphi 10 Seattle Prof.
|
Verfasst: Fr 13.02.15 10:32
Du greifst hier nicht auf die Instanz des Threads zu, die Du beim Klick von Button 1 erstellt hast. Nur ein gleicher Name reicht nicht.
Verschieb die Variablendeklaration von bThread von Button1Click in den Private-Teil des Formulars.
Dann kannst Du sowohl in Button1Click, als auch in Button2Click auf bThread zugreifen. Du darfst dann aber nicht in Button1Click oder Button2Click bThread nochmal deklarieren.
Dann klappt es auch mit bThread.Terminate
_________________ Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
|
|
Xearox
Beiträge: 260
Erhaltene Danke: 3
|
Verfasst: Fr 13.02.15 10:49
Klasse =) Du bist der Beste =)
Ist schon ziemlich komplex das Thema.
Wenn ich mal so schaue, die einen Tutorials die sind echt simpel und sehr kurz und wiederum andere sind extrem lang, welche sicherlich auch Ihre da seins Berechtigung haben.
Aber soweit so gut, klappt soweit alles. Habe wieder was dazu gelernt, also kann ich mich später damit befassen, das ganze in eine etwas komplexere Struktur einzubauen =)
Vielen Dank nochmal =)
|
|
Nersgatt
Beiträge: 1581
Erhaltene Danke: 279
Delphi 10 Seattle Prof.
|
Verfasst: Fr 13.02.15 10:55
Xearox hat folgendes geschrieben : | Klasse =) Du bist der Beste =)
Ist schon ziemlich komplex das Thema. |
Dein letzter Fehler hat aber eigentlich nichts mit dem fehlenden Verständnis der Threads zu tun, sondern mit fehlendem Verständnis, wo Variablen gültig sind.
Für den Einstieg könntest Du Dir vom Delphitreff das (kostenlose) Einsteigerbuch runterladen und durcharbeiten. Insbesondere Kapitel 4, und hier insbesondere 4.1 und 4.8. Wobei Du die anderen Kapitel aber nicht auslassen solltest.
www.delphi-treff.de/downloads/e-book/
Wenn Du Dir erst ein Grundverständnis aufbaust, dann fallen Dir neue Dinge, wie die Arbeit mit Thread (und anderen Klassen) leichter.
_________________ Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
|
|
Xearox
Beiträge: 260
Erhaltene Danke: 3
|
Verfasst: Sa 14.02.15 08:32
Guten Morgen Nersgatt,
danke für deine Antwort, die Grundlegenden Dinge von Delphi kenne ich bereits, aber es ist immer wieder sehr hilfreich, ein solches Dokument zu haben, um immer mal wieder nach zu schauen.
Daher danke für dein Link =)
|
|
|