|
![]() |
|
Registriert seit: 19. Jan 2008 Ort: Brhv 110 Beiträge Delphi 10.2 Tokyo Professional |
#1
Wenn du in einem Thread "UpdateStatus" aufrufst wird das hier im Hauptthread (durch das Synchronize) aufgerufen.
Delphi-Quellcode:
Dabei greifst du auf die (globale) Variable "Ergebnisliste" zu. Wenn ein weiterer Thread aber gerade dabei ist in diese Ergebnisliste zu schreiben, kommt es zu Problemen.
Threads[Index] := TURLCheckerThread.Create(UrlList, CriticalSection,
procedure(Msg: string) begin RichEditLog.Lines.Add(Msg); {Ergebnis als String} RichEditLog.Lines.Add(ErgebnisListe.Text); {Ergebnis als StringList} ErgebnisListe.Clear; {Nicht vergessen, sonst wird die StringList immer weiter befüllt} end, @ShouldStop, ErgebnisListe); Lösung: Auch dort die CriticalSection benutzen. Des weiteren nutzt du 1 CriticalSection für 2 unterschiedliche Listen. Das funktioniert zwar, aber du sperrst immer 2 Listen, was das ganze verlangsamen kann. Lösung: 2 CriticalSections oder TMonior.Enter(Liste) verwenden. Nur als grobe Info. Kann ich einfach eine Zweite CriticalSection einbauen und gut ist? Die eine bleibt für FUrlList und eine zweite für FResultList ??? @himitsu Sorry, auf deinen Vorschlag gehe ich erst nicht ein, bin eh schon am Limit. Für heute reicht es mir, glaube ich. Hier noch meine Änderung, jetzt sollte je Thread eine Liste benutzt werden.
Delphi-Quellcode:
EDIT, erst jetzt gesehen, da stimmt noch etwas nicht. Es reicht für heute. Sonst kommt nur noch Misst dabei raus.
procedure ButtonStartClick(Sender: TObject);
procedure ButtonAbbruchClick(Sender: TObject); procedure ButtonWeiterClick(Sender: TObject); procedure ButtonEXITClick(Sender: TObject); private { Private-Deklarationen } CriticalSection : TCriticalSection; UrlList : TStringList; ErgebnisListe : TStringList; ActiveThreads : Int64; IdleJobs : Int64; JobsFinished : Int64; procedure UpdateLabelActiveThreads; procedure UpdateLabelJobs; procedure UpdateLabelFinished; public { Public-Deklarationen } end; var Form1 : TForm1; ShouldStop : Boolean = False; implementation {$R *.dfm} type TURLCheckerThread = class(TThread) private FUrlList : TStrings; FCriticalSection : TCriticalSection; FOnStatus : TProc<TstringList>; FShouldStop : PBoolean; protected procedure Execute; override; procedure UpdateStatus(const Msg: TstringList); public constructor Create(UrlList: TStrings; CriticalSection: TCriticalSection; OnStatus: TProc<TstringList>; ShouldStop: PBoolean); end; { TWorkerThread } constructor TURLCheckerThread.Create(UrlList: TStrings; CriticalSection: TCriticalSection; OnStatus: TProc<TstringList>; ShouldStop: PBoolean); begin inherited Create(False); FUrlList := UrlList; FCriticalSection := CriticalSection; FOnStatus := OnStatus; FShouldStop := ShouldStop; FreeOnTerminate := True; end; procedure TURLCheckerThread.UpdateStatus(const Msg: TstringList); begin if Assigned(FOnStatus) then TThread.Synchronize(TThread.Current, procedure begin FOnStatus(Msg); end); end; procedure TURLCheckerThread.Execute; var FResultList : TstringList; Url : string; Http : TIdHTTP; begin Http := TIdHTTP.Create(nil); try while not Terminated and not FShouldStop^ do begin Url := ''; FCriticalSection.Acquire; try if FUrlList.Count > 0 then begin Url := FUrlList[0]; FUrlList.Delete(0); end; finally FCriticalSection.Release; end; if Url = '' then Break; Sleep(Random(2000)); {Hier kommt später meine Aufgabe} FResultList := TStringList.Create; //--> Hier geändert Pro Job wird eine Liste erstellt und zerstört try try // Http.Head(Url); FCriticalSection.Acquire; {Keine Ahnung ob es richtig ist, habe aber rausgelesen dass man StringList auf jeden Fall mit CriticalSection absichern soll} try FResultList.Add('OK: ' + Url); {Ergebnis in StringList eintragen} FResultList.Add('Zweite Zeile'); {Ergebnis in StringList eintragen} FResultList.Add('Dritte Zeile'); {Ergebnis in StringList eintragen} finally FCriticalSection.Release; end; UpdateStatus(FResultList); except on E: Exception do begin FResultList.Add('FAIL: ' + Url + ' - ' + E.Message); UpdateStatus(FResultList); end; end; finally FreeAndNil(FResultList); //--> Hier geändert Pro Job wird eine Liste erstellt und zerstört end; TThread.Synchronize(nil, procedure begin Dec(Form1.IdleJobs); Form1.UpdateLabelJobs; Inc(Form1.JobsFinished); Form1.UpdateLabelFinished; end); end; finally FreeAndNil(FResultList); FreeAndNil(Http); TThread.Synchronize(nil, procedure begin Dec(Form1.ActiveThreads); Form1.UpdateLabelActiveThreads; end); end; end; procedure TForm1.ButtonStartClick(Sender: TObject); var Threads : array[0..99] of TURLCheckerThread; Index : Integer; begin if Assigned(CriticalSection) then FreeAndNil(CriticalSection); {Falls ich nach Cancel noch mal Start drücke statt Weiter} if Assigned(UrlList) then FreeAndNil(UrlList); {Falls ich nach Cancel noch mal Start drücke statt Weiter} UrlList := TStringList.Create; CriticalSection := TCriticalSection.Create; ShouldStop := False; for Index := 1 to 100 do begin URLList.Add('http://google.com/' + IntToStr(Index)); end; LabelJobs.Caption := '100'; LabelIdle.Caption := '100'; IdleJobs := 100; JobsFinished := 0; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CriticalSection, procedure(Msg: TstringList) var ErgebnisListe : TStringList; begin RichEditLog.Lines.Add(Msg.Text); {Ergebnis als StringList} end, @ShouldStop); {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonWeiterClick(Sender: TObject); var Threads : array[0..99] of TURLCheckerThread; Index : Integer; begin ShouldStop := False; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CriticalSection, procedure(Msg: TstringList) begin RichEditLog.Lines.Add(Msg.Text); {Ergebnis als StringList} end, @ShouldStop); {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonAbbruchClick(Sender: TObject); begin ShouldStop := True; end; procedure TForm1.ButtonEXITClick(Sender: TObject); begin ShouldStop := True; Close; end; procedure TForm1.UpdateLabelActiveThreads; begin LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; procedure TForm1.UpdateLabelJobs; begin LabelIdle.Caption := IntToStr(IdleJobs); end; procedure TForm1.UpdateLabelFinished; begin LabelFinished.Caption := IntToStr(JobsFinished); end; Das Teil mag ich auch nicht, erstmal habe ich auch kein Plan wie ich es korrigieren/verbessern kann.
Delphi-Quellcode:
TThread.Synchronize(nil, procedure
begin Dec(Form1.ActiveThreads); Form1.UpdateLabelActiveThreads; end); Geändert von IMPEGA (25. Mai 2025 um 12:40 Uhr) |
![]() |
Registriert seit: 10. Jun 2003 Ort: Berlin 10.041 Beiträge Delphi 12 Athens |
#2
Ich habe einmal ein kleines Beispiel erstellt, siehe Anhang.
|
![]() |
Registriert seit: 19. Jan 2008 Ort: Brhv 110 Beiträge Delphi 10.2 Tokyo Professional |
#3
Ich habe einmal ein kleines Beispiel erstellt, siehe Anhang.
das muss ich mir in Ruhe anschauen. Für heute habe ich genug davon. |
![]() |
Registriert seit: 10. Jun 2003 Ort: Berlin 10.041 Beiträge Delphi 12 Athens |
#4
Vielleicht noch zur Erklärung:
- Eine Modifikation einer Stringliste ist aufwendiger als eine Liste mit Zahlen, weshalb diese nur gelesen wird und stattdessen die Indizes in einer Liste stehen und abgearbeitet werden. - Man könnte die Liste auch numerisch aufteilen, sprich die ersten 50 für den Thread, die nächsten für den nächsten, aber das hat einen wichtigen Nachteil: Wenn manche URLs direkt antworten und andere erst nach einer gewissen Zeit, wäre dann ggf. ein Thread viel länger beschäftigt als alle anderen. Daher wird das einzeln verteilt, so dass es insgesamt am schnellsten geht. - Die Anzahl der Threads mit 2 ist natürlich nur in der Demo so, damit man den Threadzähler sieht usw., der Wert sollte natürlich im echten Programm höher liegen. |
![]() |
Registriert seit: 19. Jan 2008 Ort: Brhv 110 Beiträge Delphi 10.2 Tokyo Professional |
#5
Erstmal,
vielen Dank für deine Vorlage. Leider, bin ich mit der Vorlage noch mehr überfordert. Wie gesagt, Coden ist nur ein Hobby von mir. Ich wage mich zwar an neue Themen ran, jedoch ist mein Wissen nicht gerade professionell. Dein Muster müsste ich wieder komplett abarbeiten, viel dazu lernen. Bei meinem Code verstehe ich das Meiste. Ich weiß zwar nicht, wie man es wirklich korrekt umsetzen soll, verstehen den Code tue ich aber schon. Das meiste davon habe ich mir nämlich selbst ausgedacht. (Natürlich, mit der freundlichen Unterstützung von Google, und viel Lesen) Ich bin sehr dankbar für die Vorlage, muss aber auf dem Boden bleiben und in meinen Möglichkeiten eine Lösung suchen. Wenn es erstmal funktioniert, kann ich versuchen mich weiter zu orientieren. Dich einfach nur kopieren, ohne Sinn und Verstand, mag ich nicht, möchte es auch nicht. Also, stelle ich erstmal weitere Fragen zu meinem Code. 1: Darf ich einfach zweite CriticalSection deklarieren ?? 2: Wie kann ich das hier besser umsetzen (Idee mit Erklärung, oder kleiner Muster wäre super) Dec(Form1.ActiveThreads); Form1.UpdateLabelActiveThreads; 3: Die StringList erstelle ich nun im Thread, eine pro Job und lösche sie, wen fertig. Gibt es damit Ärger? oder darf ich es so machen?
Delphi-Quellcode:
Falls ich damit kaum zum Erfolg kommen sollte, bitte auch aufklären warum, dann muss ich neuen Ansatz suchen.
procedure TURLCheckerThread.Execute;
var FErgebnis : TstringList; // --> Frage Nr. 3 Url : string; Http : TIdHTTP; begin Http := TIdHTTP.Create(nil); try while not Terminated and not FShouldStop^ do begin Url := ''; FCS1.Acquire; // --> Frage Nr. 1 try if FUrlList.Count > 0 then begin Url := FUrlList[0]; FUrlList.Delete(0); end; finally FCS1.Release; // --> Frage Nr. 1 end; if Url = '' then Break; Sleep(Random(2000)); {Hier kommt später meine Aufgabe} FErgebnis := TStringList.Create; // --> Frage Nr. 3 try try // Http.Head(Url); FCS2.Acquire; // --> Frage Nr. 1 try FErgebnis.Add('OK: ' + Url); FErgebnis.Add('Zweite Zeile'); FErgebnis.Add('Dritte Zeile'); finally FCS2.Release; // --> Frage Nr. 1 end; UpdateStatus(FErgebnis); // --> Frage Nr. 3 except on E: Exception do begin FErgebnis.Add('FAIL: ' + Url + ' - ' + E.Message); UpdateStatus(FErgebnis); end; end; finally FreeAndNil(FErgebnis); // --> Frage Nr. 3 end; TThread.Synchronize(nil, procedure begin Dec(Form1.IdleJobs); // --> Frage Nr. 2 Form1.UpdateLabelJobs; // --> Frage Nr. 2 Inc(Form1.JobsFinished); // --> Frage Nr. 2 Form1.UpdateLabelFinished; // --> Frage Nr. 2 end); end; finally FreeAndNil(FErgebnis); FreeAndNil(Http); TThread.Synchronize(nil, procedure begin Dec(Form1.ActiveThreads); // --> Frage Nr. 2 Form1.UpdateLabelActiveThreads; // --> Frage Nr. 2 end); end; end; Damit komme ich aber einigermaßen klar, also wäre es schon mein Favorit. Auch wenns nicht perfekt ist. ![]() . |
![]() |
Registriert seit: 19. Jan 2008 Ort: Brhv 110 Beiträge Delphi 10.2 Tokyo Professional |
#6
Ich habe ein wenig nachgebessert. Kann jemand noch mal den Code anschauen?
Besser kriege ich es wohl nicht hin.
Delphi-Quellcode:
procedure FormDestroy(Sender: TObject);
procedure ButtonStartClick(Sender: TObject); procedure ButtonAbbruchClick(Sender: TObject); procedure ButtonWeiterClick(Sender: TObject); procedure ButtonEXITClick(Sender: TObject); private { Private-Deklarationen } CSection1 : TCriticalSection; CSection2 : TCriticalSection; UrlList : TStringList; ErgebnisListe : TStringList; ActiveThreads : Int64; IdleJobs : Int64; JobsFinished : Int64; procedure UpdateLabelActiveThreads(Sender: TObject); procedure UpdateLabelJobs(Sender: TObject); procedure UpdateLabelFinished(Sender: TObject); public { Public-Deklarationen } end; var Form1 : TForm1; ShouldStop : Boolean = False; implementation {$R *.dfm} type TURLCheckerThread = class(TThread) private FUpdateAktiv : TNotifyEvent; {<--- HIER} FUpdateJobs : TNotifyEvent; {<--- HIER} FUpdateFertig : TNotifyEvent; {<--- HIER} FUrlList : TStrings; FCSection1 : TCriticalSection; FCSection2 : TCriticalSection; FOnStatus : TProc<TstringList>; FShouldStop : PBoolean; FTimeOut : Word; {<--- HIER} protected procedure Execute; override; procedure UpdateStatus(const Msg: TstringList); public constructor Create(UrlList: TStrings; CSection1, CSection2: TCriticalSection; OnStatus: TProc<TstringList>; ShouldStop: PBoolean); property OnUpdateActive : TNotifyEvent read FUpdateAktiv write FUpdateAktiv; {<--- HIER} property OnUpdateJobs : TNotifyEvent read FUpdateJobs write FUpdateJobs; {<--- HIER} property OnUpdateFertig : TNotifyEvent read FUpdateFertig write FUpdateFertig; {<--- HIER} property TimeOut : Word read FTimeOut write FTimeOut; {<--- HIER} end; { TWorkerThread } constructor TURLCheckerThread.Create(UrlList: TStrings; CSection1, CSection2: TCriticalSection; OnStatus: TProc<TstringList>; ShouldStop: PBoolean); begin inherited Create(False); FUrlList := UrlList; FCSection1 := CSection1; FCSection2 := CSection2; FOnStatus := OnStatus; FShouldStop := ShouldStop; FreeOnTerminate := True; end; procedure TURLCheckerThread.UpdateStatus(const Msg: TstringList); begin if Assigned(FOnStatus) then TThread.Synchronize(TThread.Current, procedure begin FOnStatus(Msg); end); end; procedure TURLCheckerThread.Execute; var FErgebnis : TstringList; Url : string; Http : TIdHTTP; begin Http := TIdHTTP.Create(nil); Http.ConnectTimeout := FTimeOut; // 8000 Http.ReadTimeout := FTimeOut; try while not Terminated and not FShouldStop^ do begin Url := ''; FCSection1.Acquire; try if FUrlList.Count > 0 then begin Url := FUrlList[0]; FUrlList.Delete(0); end; finally FCSection1.Release; end; if Url = '' then Break; Sleep(Random(2000)); {Hier kommt später meine Aufgabe} FErgebnis := TStringList.Create; try try // Http.Head(Url); FCSection2.Acquire; {Keine Ahnung ob es richtig ist, habe aber rausgelesen dass man StringList auf jeden Fall mit CriticalSection absichern soll} try FErgebnis.Add('OK: ' + Url); {Ergebnis in StringList eintragen} FErgebnis.Add('Zweite Zeile'); FErgebnis.Add('Dritte Zeile'); finally FCSection2.Release; end; UpdateStatus(FErgebnis); except on E: Exception do begin FErgebnis.Add('FAIL: ' + Url + ' - ' + E.Message); UpdateStatus(FErgebnis); end; end; finally FreeAndNil(FErgebnis); end; if Assigned(FUpdateJobs) then begin TThread.Synchronize(nil, procedure begin FUpdateJobs(Self); end); end; if Assigned(FUpdateFertig) then begin TThread.Synchronize(nil, procedure begin FUpdateFertig(Self); end); end; end; finally FreeAndNil(FErgebnis); FreeAndNil(Http); if Assigned(FUpdateAktiv) then begin TThread.Synchronize(nil, procedure begin FUpdateAktiv(Self); end); end; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreeAndNil(ErgebnisListe); FreeAndNil(UrlList); FreeAndNil(CSection1); FreeAndNil(CSection2); end; procedure TForm1.ButtonStartClick(Sender: TObject); var Threads : array[0..100] of TURLCheckerThread; Index : Integer; begin if Assigned(CSection1) then FreeAndNil(CSection1); {Falls ich nach Cancel noch mal Start drücke statt Weiter} if Assigned(CSection2) then FreeAndNil(CSection2); if Assigned(UrlList) then FreeAndNil(UrlList); UrlList := TStringList.Create; CSection1 := TCriticalSection.Create; CSection2 := TCriticalSection.Create; ShouldStop := False; for Index := 0 to 200 do begin URLList.Add('http://google.com/' + IntToStr(Index)); end; LabelJobs.Caption := '100'; LabelIdle.Caption := '100'; IdleJobs := 100; Gauge1.MaxValue := 100; Gauge1.Progress := 0; JobsFinished := 0; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CSection1, CSection2, procedure(Msg: TstringList) var ErgebnisListe : TStringList; begin RichEditLog.Lines.Add(Msg.Text); {Ergebnis als StringList} end, @ShouldStop); Threads[Index].TimeOut := SpinEditTimeout.Value; Threads[Index].OnUpdateActive := UpdateLabelActiveThreads; Threads[Index].OnUpdateJobs := UpdateLabelJobs; Threads[Index].OnUpdateFertig := UpdateLabelFinished; {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonWeiterClick(Sender: TObject); var Threads : array[0..100] of TURLCheckerThread; Index : Integer; begin ShouldStop := False; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CSection1, CSection2, procedure(Msg: TstringList) begin RichEditLog.Lines.Add(Msg.Text); {Ergebnis als StringList} end, @ShouldStop); Threads[Index].TimeOut := SpinEditTimeout.Value; Threads[Index].OnUpdateActive := UpdateLabelActiveThreads; Threads[Index].OnUpdateJobs := UpdateLabelJobs; Threads[Index].OnUpdateFertig := UpdateLabelFinished; {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonAbbruchClick(Sender: TObject); begin ShouldStop := True; end; procedure TForm1.ButtonEXITClick(Sender: TObject); begin ShouldStop := True; Close; end; procedure TForm1.UpdateLabelActiveThreads; begin Dec(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; procedure TForm1.UpdateLabelJobs(Sender: TObject); begin Dec(Form1.IdleJobs); LabelIdle.Caption := IntToStr(IdleJobs); end; procedure TForm1.UpdateLabelFinished; begin Inc(Form1.JobsFinished); LabelFinished.Caption := IntToStr(JobsFinished); Gauge1.Progress := Gauge1.Progress + 1; end; |
![]() |
Registriert seit: 10. Jun 2003 Ort: Berlin 10.041 Beiträge Delphi 12 Athens |
#7
Du packst die Threads nach wie vor in Threads[Index] und greifst darauf nach dem Start der Threads (du erstellt diese ja nicht suspended, das ist der Parameter an Create) noch zu.
Erstens kann das wie gesagt knallen und zweitens wird das Timeout in Execute ggf. schon gelesen, bevor du es von außen setzt. Du musst alle Werte im Konstruktor übergeben oder suspended starten. Geändert von jaenicke (26. Mai 2025 um 20:09 Uhr) |
![]() |
Registriert seit: 15. Mär 2007 4.238 Beiträge Delphi 12 Athens |
#8
Ich habe einmal ein kleines Beispiel erstellt, siehe Anhang.
![]() Ich frage mich, weil es eine globale Funktion ist, welche von allen Seiten aus angefragt werden könnte, ob es nicht threadsicherer würde, wenn man die Parameter klonen würde? Also hier
Delphi-Quellcode:
Ich habe bei der direkten Nutzung von Parametern wie AUrlList über zwei anonyme Funktionen hinweg immer so meine Bauchschmerzen, ob sich da drin zwischendurch nicht doch was verändert hat.
class procedure TUrlChecker.Check( const AUrlList : TStrings;
const AStatusCallback : TStatusCallback; ThreadCount : Integer; const AOnFinished : TFinishedCallback ); var LUrlList : TStringList; begin LUrlList : TStringList.Create; // Better clone, to ensure higher threadsafety?? LUrlList.AddStrings( AUrlList ); TTask.Run( procedure var WorkQueue : TThreadedQueue< NativeUInt >; Tasks : TArray<ITask>; I : Integer; begin // Intern nur die Kopie LUrlList, statt AUrlList verwenden if not Assigned( LUrlList ) or not Assigned( AStatusCallback ) then Exit; ... In der Praxis wird es wohl 100% ausreichen, weil man so eine Funktion ja nur an einer bestimmten Stelle nutzt, die man gut beobachten kann, normalerweise. Aber falls nicht, dann "better safe than sorry", solche Fehler sind wohl schwer zu finden. Oder gibt es gute Gründe dafür, dass ich mir hier zu viele Sorgen wegen der Parameter mache ![]() Geändert von Rollo62 (27. Mai 2025 um 08:58 Uhr) |
![]() |
Registriert seit: 10. Jun 2003 Ort: Berlin 10.041 Beiträge Delphi 12 Athens |
#9
Mit dem aktuellen Delphi 12 kannst du diesen impliziten Scope, der die Werte solcher Variablen enthält, direkt in der Variablenliste sehen. Das Feature ist echt gut. Das hilft denke ich beim Verständnis deutlich weiter.
Wenn du z.B. einen out-Parameter dort hättest, würdest du die Meldung bekommen, dass dieser Wert nicht erfasst werden kann. Denn da der Funktionsaufruf schon vorbei sein kann, kann man das nicht über den Scope abbilden. Hier in diesem Fall hast du natürlich Recht: Die Stringliste könnte nach dem Aufruf freigegeben oder verändert werden. Ich habe mich darauf verlassen, dass während der Laufzeit der Threads niemand das Memo ändert. Mit deiner Änderung könnte man das Problem umgehen. |
![]() |
Registriert seit: 7. Aug 2008 Ort: Brandenburg 1.490 Beiträge Delphi 12 Athens |
#10
Der Code enthält noch einige Probleme:
"ErgebnisListe" Wird an zwei Stellen deklariert (gefährlich), aber nur eine Variable wird tatsächlich initialisiert und wieder freigegeben, ansonsten aber nicht verwendet, also überflüssig. "CSection2" Da auf die Stringliste "FErgebnis" niemals von zwei verschiedenen Thread gleichzeitig zugegriffen wird, ist diese Sektion überflüssig. So wie diese jetzt verwendet wird, kann die auch nicht wirken. Sinnvoller wäre an dieser Stelle statt der Stringliste den fertigen Protokollstring zurückzugeben ( FOnStatus : TProc<string>; ) "FErgebnis" Wird noch einmal freigegeben, obwohl das nicht notwendig ist. "ShouldStop" Die Variable gehört nicht global deklariert, sondern zu diesem Anwendungsfall "private". Der Inhalt der Variable wird per Referenz bei Erzeugung der Threads übergeben und dort als Referenz gespeichert. Der Inhalt wird gleichzeitig durch die einzelnen Threads gelesen, aber auch durch den Hauptthread geändert. Alle Zugriffe auf den Inhalt der Variablen müssen deshalb abgesichert werden (z.B. mit "CSection1"). "ButtonStartClick" Bei erneutem Aufruf werden alle Objekte freigegeben. Es wird aber nicht geprüft, ob eventuell noch Threads existieren, die mit diesen Objekten arbeiten. Das würde dann vermutlich zum Absturz führen. "ButtonWeiterClick" Doppelter Code mit "ButtonStartClick", in eigene Untermethode auslagern. "FUpdateAktiv" Das Ereignis gehört eher in OnTerminate, das spart auch das Synchronize. "FUpdateJobs" und "FUpdateFertig" Zu einem Ereignis zusammenfassen und dort beide Aufgaben erledigen. Bei jedem Synchronize wird der Thread angehalten. Der Anwendungsfall könnte auf TThread.Queue() umgestellt werden. |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |