| Autor |
Beitrag |
Bergmann89
      
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)
|
Verfasst: 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.
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; 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; 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
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: So 03.01.10 22:47
Moin!
Bergmann89 hat folgendes geschrieben : | | Hat jmd von euch ne Idee woran das liegen könnte? |
Ja, du greifst unsynchronisiert auf VCL-Controls zu.  Details im Forum.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 03.01.10 22:53
Das kann auch nicht klappen, du greifst aus dem Thread heraus ohne Synchronisation auf dein Formular zu...
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. 
|
|
Bergmann89 
      
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)
|
Verfasst: 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
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
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)
|
Verfasst: 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
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
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)
|
Verfasst: 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
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 03.01.10 23:31
Bergmann89 hat folgendes geschrieben : | | 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 
      
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)
|
Verfasst: 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...
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 SetLyricGridRow(i+1); end; if Terminated then begin break; end; MP3.GetAudioInfo(FileList[i]); if SkipIfExists and (MP3.LyricCount > 0) then begin 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); SetLyricGridCell(GRID_ACTIO, i+1, 'Lyric added'); end else begin SetLyricGridCell(GRID_ACTIO, i+1, 'Lyric not found'); end; end else begin SetLyricGridCell(GRID_ACTIO, i+1, 'Titel not found'); end; 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
|
Verfasst: Mo 04.01.10 09:01
Und wo ist das Synchronize? Ob du nun schreibst:
Delphi-Quelltext 1:
| Form1.LyricGrid.Row := i+1; |
oder den Aufruf in eine Methode auslagerst:
Delphi-Quelltext
macht doch irgendwie keinen Unterschied oder?
|
|
Bergmann89 
      
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)
|
Verfasst: Mo 04.01.10 13:58
Hey,
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
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: Mo 04.01.10 14:41
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 
      
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)
|
Verfasst: 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
      
Beiträge: 1054
Erhaltene Danke: 78
Win 7, Ubuntu 9.10
Delphi 2007 Pro, C++, Qt
|
Verfasst: 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
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: 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 
      
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)
|
Verfasst: Mo 04.01.10 15:58
Hey,
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:
Quelltext 1:
| [Fehler] Unit1.pas(233): Diese Form des Methodenaufrufs ist nur für Klassenmethoden erlaubt |
Und so gehts auch nich:
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:
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
      
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: 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
|
Verfasst: Mo 04.01.10 18:38
|
|
alias5000
      
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)
|
Verfasst: Mo 04.01.10 19:09
Also, was jetzt noch in Frage kommt, sind Stellen wie diese:
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
|
|
|