Autor Beitrag
Bergmann89
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: So 03.01.10 22:45 
Hey,

ich benutz in meinem Programm Threads, damit die GUI beim rechnen nicht hängen bleibt. Aber der Thread wird aus irgendeinem Grund vorzeitig beendet. Aber auch immer an unterschiedlichen Stellen. Gibts sowas wie n TimeOut oder sowas? Oderliegt es doch an was anderem? Hier mal der Code der Execute-Prozedur.
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:
procedure TAutoSearchThread.Execute;
var Int: TInterpret;
var MP3: TMP3File;
var Titel: TTitel;
var Lyric: WideString;
var i: Integer;
begin
  MP3 := TMP3File.Create;
  Int := TInterpret.Create;
  for i := 0 to FileList.Count-1 do begin
    if Form1.AutoScrollCB.Checked then
      Form1.LyricGrid.Row := i+1;
    if Terminated then begin
      break; //diese Zeile wird nicht ausgeführt
    end;
    MP3.GetAudioInfo(FileList[i]);
    if Form1.SkipIfExists.Checked and (MP3.LyricCount > 0) then begin
      Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'skipped';
      continue;
    end;
    if LowerCase(Int.Name) <> LowerCase(MP3.Interpret) then
      Int.LoadFromHTML(MP3.Interpret);
    Titel := Int.FindTitel(MP3.Titel);
    if Assigned(Titel) then begin
      Lyric := Titel.GetLyric;
      if Lyric <> '' then begin
        MP3.AddLyric('eng', MP3.Interpret+' - '+MP3.Titel, Lyric);
        Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Lyric added';
      end else begin
        Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Lyric not found';
      end;
    end else begin
      Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Titel not found';
    end;
    Form1.LyricGrid.Cells[GRID_COUNT,i+1] := IntToStr(MP3.LyricCount);
    MP3.SaveAudioInfo;
  end;
  Terminate; //diese Zeile wird auch nicht ausgeführt
end;

Hat jmd von euch ne Idee woran das liegen könnte?

MfG & Thx Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 03.01.10 22:47 
Moin!

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Hat jmd von euch ne Idee woran das liegen könnte?
Ja, du greifst unsynchronisiert auf VCL-Controls zu. :idea: ;) Details im Forum. :D

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.01.10 22:53 
Das kann auch nicht klappen, du greifst aus dem Thread heraus ohne Synchronisation auf dein Formular zu... :roll:

Dass das nicht geht steht explizit drin, wenn du über Datei --> Neu einen Thread erzeugst. Das muss alles synchronisiert werden, da die VCL nicht threadsicher ist. Alles was mit visuellen Komponenten oder graphischen Elementen zu tun hat (auch TBitmap) gehört in den Hauptthread bzw. muss synchronisiert werden, so dass es in dessen Kontext läuft.

// EDIT:
Huch, da stehts ja schon. :gruebel:
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: So 03.01.10 23:01 
Hey,

das ich die Threads bei komplexeren Sachen voreinander schützten muss weiß ich (da hab ich in der schule ma aufgepasst^^). Aber da es sich ja bloß um einige Zuweißungen handelt dachte ich das geht auch so, naja...
Also muss ich alle Zugriffe vom Thread auf die Forms synchronisieren. Muss ich da jetzt zu jeder Zuweißung ne Extra Prozedur schrieben, oder geht das auch anders? Weil die Synchronize-Prozedur ja Prozeduren als Parameter erwartet.

MfG Bergmann

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.01.10 23:05 
Du machst zum Beispiel eine Prozedur zum Auslesen der Daten und eine zur Rückgabe der Daten. Eigentlich ist das aber ohnehin keine gute Idee. Übergib die Daten lieber explizit an den Thread und lasse dich z.B. per Event von der Fertigstellung der Aufgabe benachrichtigen. Dann kannst du die Ergebnisse auslesen.

Wenn du das genauso wie du es jetzt hast mit Synchronisation umsetzt, kannst du dir den Thread sparen, da wird das ganze nur unnötig langsam. Denn da du ständig auf den Hauptthread zugreifen müsstest und den pausieren müsstest, bringt dir der Thread dann rein gar nix.

Ein Thread ist dafür gedacht unabhängig im Hintergrund zu rechnen und nur sporadisch Ergebnisse zurückzuliefern oder nur am Ende, aber nicht ständig.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: So 03.01.10 23:09 
HM, dann sollte ich vlt nur die Prozedur in nen Thread packen, die mit der HTTP-Komponente arbeitet... Ochnö, da muss ich jetz alles umbauen -.- Naja das nächste ma bin ich schlauer ^^ Danke.

€: noch ne Frage. Um wieviel würde das denn langsamer werden, weil wenns net viel is solls mich net stören. Die Zugriffe auf die Forms sind bloß Rückmeldungen für den User, die kömnnt ich ja auch raus nehmen...

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.01.10 23:17 
Naja, was du machen kannst wäre auch, dass du nur alle soundsoviele Einträge die Ergebnisse in der GUI anzeigst. Oder dass du die Zeit nimmst und alle 5 Sekunden aktualisierst oder so. Dadurch verhinderst du, dass der Thread zu oft den Hauptthread pausiert und auf die GUI zugreifst.

Es gibt aber auch noch andere Kommunikationsmöglichkeiten zwischen Threads, aber ich habe irgendwie so das Gefühl als sei das mit Kanonen auf Spatzen geschossen und so...
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: So 03.01.10 23:27 
Und wenn ich mit dem MainThread synchronisieren muss, dann bleibt die GUI wieder hängen, richtig? Dannmuss ich mir wohl doch die Mühe machen und das alles nochma umbauen...

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.01.10 23:31 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Und wenn ich mit dem MainThread synchronisieren muss, dann bleibt die GUI wieder hängen, richtig?
Schon, aber nur sehr kurz (wenn du es richtig machst^^), das merkt man dann kaum, aber da man gleichzeitig die Rückmeldung sieht, sollte das ja auch kein Problem sein.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: So 03.01.10 23:53 
Hab jetzt erstma probiert meine Thread anzupassen. Aber er bricht immer noch ab, obwohl ich nur noch Synchronized auf Form1 zugreife...
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:
procedure TAutoSearchThread.WriteLyricGridCell;
begin
  Form1.LyricGrid.Cells[fCol, fRow] := fMsg;
end;

procedure TAutoSearchThread.WriteLyricGridRow;
begin
  Form1.LyricGrid.Row := fRow;
end;

procedure TAutoSearchThread.SetLyricGridCell(Col, Row: Integer; Msg: String);
begin
  fRow := Row;
  fCol := Col;
  fMsg := Msg;
  Synchronize(WriteLyricGridCell);
end;

procedure TAutoSearchThread.SetLyricGridRow(Row: Integer);
begin
  fRow := Row;
  Synchronize(WriteLyricGridRow);
end;

procedure TAutoSearchThread.Execute;
var Int: TInterpret;
var MP3: TMP3File;
var Titel: TTitel;
var Lyric: WideString;
var i: Integer;
begin
  MP3 := TMP3File.Create;
  Int := TInterpret.Create;
  for i := 0 to FileList.Count-1 do begin
    if AutoScroll then begin
      //Form1.LyricGrid.Row := i+1;
      SetLyricGridRow(i+1);
    end;
    if Terminated then begin
      break;
    end;
    MP3.GetAudioInfo(FileList[i]);
    if SkipIfExists and (MP3.LyricCount > 0) then begin
      //Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'skipped';
      SetLyricGridCell(GRID_ACTIO, i+1, 'skipped');
      continue;
    end;
    if LowerCase(Int.Name) <> LowerCase(MP3.Interpret) then
      Int.LoadFromHTML(MP3.Interpret);
    Titel := Int.FindTitel(MP3.Titel);
    if Assigned(Titel) then begin
      Lyric := Titel.GetLyric;
      if Lyric <> '' then begin
        MP3.AddLyric('eng', MP3.Interpret+' - '+MP3.Titel, Lyric);
        //Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Lyric added';
        SetLyricGridCell(GRID_ACTIO, i+1, 'Lyric added');
      end else begin
        //Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Lyric not found';
        SetLyricGridCell(GRID_ACTIO, i+1, 'Lyric not found');
      end;
    end else begin
      //Form1.LyricGrid.Cells[GRID_ACTIO, i+1] := 'Titel not found';
      SetLyricGridCell(GRID_ACTIO, i+1, 'Titel not found');
    end;
    //Form1.LyricGrid.Cells[GRID_COUNT,i+1] := IntToStr(MP3.LyricCount);
    SetLyricGridCell(GRID_COUNT, i+1, IntToStr(MP3.LyricCount));
    MP3.SaveAudioInfo;
  end;
  Terminate;
end;
Is doch so richtig, oder hab ich da was falsch verstanden?

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 04.01.10 09:01 
Und wo ist das Synchronize? Ob du nun schreibst:
ausblenden Delphi-Quelltext
1:
Form1.LyricGrid.Row := i+1;					

oder den Aufruf in eine Methode auslagerst:
ausblenden Delphi-Quelltext
1:
SetLyricGridRow(i+1);					

macht doch irgendwie keinen Unterschied oder?
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mo 04.01.10 13:58 
Hey,

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TAutoSearchThread.SetLyricGridCell(Col, Row: Integer; Msg: String);
begin
  fRow := Row;
  fCol := Col;
  fMsg := Msg;
  Synchronize(WriteLyricGridCell);
end;

procedure TAutoSearchThread.SetLyricGridRow(Row: Integer);
begin
  fRow := Row;
  Synchronize(WriteLyricGridRow);
end;


;)

MfG

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
platzwart
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: Mo 04.01.10 14:41 
ausblenden 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:
procedure TForm1.WriteLyricGridCell(fCol, fRow: Integer; fMsg: String);
begin
  LyricGrid.Cells[fCol, fRow] := fMsg;
end;

procedure TForm1.WriteLyricGridRow(fRow: Integer);
begin
  LyricGrid.Row := fRow;
end;

procedure TAutoSearchThread.SetLyricGridCell(Col, Row: Integer; Msg: String);
begin
  fRow := Row;
  fCol := Col;
  fMsg := Msg;
  Synchronize(WriteLyricGridCell(fCol, fRow, fMsg));
end;

procedure TAutoSearchThread.SetLyricGridRow(Row: Integer);
begin
  fRow := Row;
  Synchronize(WriteLyricGridRow(fRow));
end;


Muss man das nicht so synchronisieren?!? Ansonsten synchronisierst du mit einer Methode der eigenen Threadklasse und nicht mit der TForm1...

_________________
Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mo 04.01.10 15:32 
Ich dachte das is egal, weil in der Hilfe steht, das die Methode dann im Kontext des Main-Thread ausgeführt wird, also is es ja eigentlich egal, wem sie gehört, oder?

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
platzwart
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1054
Erhaltene Danke: 78

Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
BeitragVerfasst: Mo 04.01.10 15:47 
Probiers mal bitte aus... ;)

_________________
Wissenschaft schafft Wissenschaft, denn Wissenschaft ist Wissenschaft, die mit Wissen und Schaffen Wissen schafft. (myself)
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8554
Erhaltene Danke: 481

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Mo 04.01.10 15:58 
Das runterladen der Daten, machst du sicher mit den Indys. Liegen diese als Komponente auf der Form, oder erzeugst du die im Kontext des Threads?

Was ist FileList? Ist das eine TObjectlist, oder etwas aus der VCL? Ist sichergestellt, dass darauf nciht zugegriffen wird, während der Thread läuft?

_________________
We are, we were and will not be.
Bergmann89 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1742
Erhaltene Danke: 72

Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
BeitragVerfasst: Mo 04.01.10 15:58 
Hey,
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.WriteGrid(Col, Row: Integer; Msg: String);
begin
  LyricGrid.Cells[Col, Row] := Msg;
end;

Synchronize(TForm1.WriteGrid(GRID_ACTIO, i+1, 'skipped')); //-->Fehler
Fehler:
ausblenden Quelltext
1:
[Fehler] Unit1.pas(233): Diese Form des Methodenaufrufs ist nur für Klassenmethoden erlaubt					


Und so gehts auch nich:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TAutoSearchThread.WriteGrid(Col, Row: Integer; Msg: String);
begin
  Form1.LyricGrid.Cells[Col, Row] := Msg;
end;

Synchronize(WriteGrid(GRID_ACTIO, i+1, 'skipped')); //-->Fehler
Fehler:
ausblenden Quelltext
1:
[Fehler] Unit1.pas(233): Es gibt keine überladene Version von 'Synchronize', die man mit diesen Argumenten aufrufen kann					


@Gausi: Der HTTPClient wird im Kontext des Threads erstellt. FileList is ne TStingList. Die gehört auch dem Thread und wird zuvor mit FileList.Assign(); gefüllt.

MfG

_________________
Ich weiß nicht viel, lern aber dafür umso schneller^^
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Mo 04.01.10 16:03 
Soweit ich mich erinner, schickt Synchronize eine Message an den Hauptthread inklusive pointer auf die auszuführende Methode, und wartet dann solange, bis das verarbeitet ist.
Somit wird Synchronize immer im MainThread ausgeführt.

Auch kann man bei der zu synchronisierenden Methode keine Parameter mehr mitgeben
-> Die Methode von Bergmann89 war schon ok.

_________________
PROGRAMMER: A device for converting coffee into software.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 04.01.10 18:38 
user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Hey,

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TAutoSearchThread.SetLyricGridCell(Col, Row: Integer; Msg: String);
begin
  fRow := Row;
  fCol := Col;
  fMsg := Msg;
  Synchronize(WriteLyricGridCell);
end;

procedure TAutoSearchThread.SetLyricGridRow(Row: Integer);
begin
  fRow := Row;
  Synchronize(WriteLyricGridRow);
end;


;)

MfG

Mist, überlesen. Sorry.
alias5000
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: Mo 04.01.10 19:09 
Also, was jetzt noch in Frage kommt, sind Stellen wie diese:
ausblenden Delphi-Quelltext
1:
2:
3:
    if Terminated then begin
      break;
    end;


Schau mal bitte, ob du aus Versehen irgendwo den Thread beendest. Oder Debug dem ganzen mal etwas nach, bzw. lass ein bisschen Logging mitlaufen, um ne Regelmäßigkeit zu finden.

gruß
alias5000

_________________
Programmers never die, they just GOSUB without RETURN