Autor Beitrag
Xearox
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260
Erhaltene Danke: 3



BeitragVerfasst: 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.

ausblenden volle Höhe 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:
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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TMeinThread1 = class(TThread)
  protected
     procedure Ausgabe; // nur mir Synchronize aufrufen da zugriff auf Hauptthread
     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;

{###############################################################################
####################### Thread Nummer 1 ########################################
###############################################################################}


procedure TMeinThread1.Ausgabe;
begin
  Form1.Memo1.Lines.Add('Text');
end;

procedure TMeinThread1.Execute;
begin
  Synchronize(Ausgabe);
end;

{###############################################################################
####################### Thread Nummer 2 ########################################
###############################################################################}


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;
  //ShowMessage('Bin hier');
  Synchronize(Ausgabe);
end;

procedure TMeinThread2.MyTimerEvent(Sender: TObject);
begin
  Z := Z + 1;
  //ShowMessage('test');
end;

{###############################################################################
####################### Thread Ende ############################################
###############################################################################}


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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: 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:

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260
Erhaltene Danke: 3



BeitragVerfasst: Fr 13.02.15 10:29 
user profile iconNersgatt hat folgendes geschrieben Zum zitierten Posting springen:
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:

ausblenden 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
ausblenden 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

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: 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. :D

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 :D

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
Xearox Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260
Erhaltene Danke: 3



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Fr 13.02.15 10:55 
user profile iconXearox hat folgendes geschrieben Zum zitierten Posting springen:
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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260
Erhaltene Danke: 3



BeitragVerfasst: 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 =)