![]() |
Delphi einfaches Multithread Beispiel.
Hier ein einfaches Multithread Beispiel ohne viel Schnörkel:
Beschreibung: Es wird Speicher reserviert für 20 Threads. 20 Threads werden gestartet über ein array of TmyThread. Gestartete Threads schreiben in ein Memo ihre Thread ID. Die Threads zählen ein integer hoch in Form1.caption. Je mehr threads gestartet desto schneller. Wird ein Thread geschlossen, so entfernt er seine Thread ID aus dem Memo. Über den zweiten Button können alle Threads über eine Schleife gleichzeitig beendet werden. Wer Verbesserungsvorschläge hat kann diese natürlich hinzufügen :thumb: Es werden benötigt: 2 Buttons und 1 Memo. --Die aktuelle korrigierte Version findet sich weiter ![]()
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Comctrls, System.ImageList, Vcl.ImgList, Vcl.StdCtrls; type TmyThread = class(TThread) procedure Execute; override; procedure Synthreads; procedure Syni; end; TForm1 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; i:integer =0; var threads: array of cardinal; var meinThread: array of TmyThread; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i : integer; begin SetLength(meinthread, 20); for i := 0 to high(meinThread) do meinThread[i]:= TmyThread.Create(false); end; { TmyThread } procedure TmyThread.Execute; var z: integer; var cnt: integer; begin inherited; SetLength(threads, length(threads)+1); threads[(high(threads))] := self.ThreadID; SYNCHRONIZE(Self.Synthreads); for z := 0 to 50 do begin inc(i); sleep(random(500)); Synchronize(Syni); if Terminated then break; end; for cnt:= low(threads) to High(threads) do if threads[cnt] = self.ThreadID then begin threads[cnt] := threads[high(threads)]; SetLength(threads, length(threads)-1); end; Synchronize(Synthreads); end; procedure TmyThread.Syni; begin form1.Caption:= inttostr(i); end; procedure TmyThread.Synthreads; var line: integer; begin form1.memo1.clear; for line := Low(threads) to High(threads) do form1.Memo1.Lines.Add(inttostr(threads[line])); end; procedure TForm1.Button2Click(Sender: TObject); var i:integer; begin if Length(meinThread) >0 then for I := 0 to high(meinThread) do if ((meinThread[i] <> nil ) and (meinThread[i].Terminated = false)) then meinThread[i].Terminate; end; end. |
AW: Delphi einfaches Multithread Beispiel.
Ich bin kein MuiThreading-Profi aber ich finde das hier solltest du nicht als Beispiel posten.
Ich würde es grundlegend anders machen und Synchronize komplett rausschmeißen. Sendmessage/Postmessage und dann abarbeiten. Dann würde ich auch niemals einen Thread mit Terminate beenden. Eher Events oder so. Und dann dieser Vergleich auf False. Von globalen Variablen fange ich gar nicht erst an. Ich werde jetzt sicher wieder von allen Seiten angemacht, weil ich nur am meckern bin. Aber das ist kein guter Beispielcode. |
AW: Delphi einfaches Multithread Beispiel.
Die Nutzung von globalen Variablen wird nicht gern gesehen. Es gibt keinen Grund, die nicht zumindest in den Implementationsabschnitt zu verfrachten. Außerdem ist hier das falsche Schlüsselwort var verwendet, wobei threadvar keine automatische Speicherverwaltung auch nicht für nicht-primitive Nicht-Klassen hat. Und die Namen der Variablen überschneiden sich. Man würde allgemein keine Variable i nennen, die keine lokale Zählvariable ist.
|
AW: Delphi einfaches Multithread Beispiel.
Guten Abend :-)
Zitat:
Zitat:
Zitat:
Aber jetzt zum interessanten Teil - ich habe mal kommentiert:
Delphi-Quellcode:
procedure TmyThread.Execute;
var z: integer; cnt: integer; begin inherited; // Unnötig SetLength(threads, length(threads)+1); // Gefährlich - SetLength ist NICHT thread-safe! threads[(high(threads))] := self.ThreadID; SYNCHRONIZE(Self.Synthreads); for z := 0 to 50 do begin inc(i); // Integer-zugriff ist atomar und damit i.O. (soweit ich weiß) sleep(random(500)); Synchronize(Syni); if Terminated then break; end; for cnt:= low(threads) to High(threads) do if threads[cnt] = self.ThreadID then begin threads[cnt] := threads[high(threads)]; SetLength(threads, length(threads)-1); // Auch hier eine race condition, mehrere Thread könnten SetLength gleichzeitig aufrufen! // Außerdem ein Speicherleck, der Thread wird nicht freigegeben end; Synchronize(Synthreads); end; procedure TForm1.Button2Click(Sender: TObject); var i:integer; begin if Length(meinThread) >0 then // Überflüssig, die Schleife läuft ohne Elemente eh nicht for I := 0 to high(meinThread) do // Vergleich auf nil _aktuell_ überflüssig, da du es nie auf nil setzt. Zudem auch der check auf Terminated überflüssig - zweimal aufrufen schadet nicht. if ((meinThread[i] <> nil ) and (meinThread[i].Terminated = false)) then meinThread[i].Terminate; end; |
AW: Delphi einfaches Multithread Beispiel.
Guten Morgen!
Habe alles nochmal überarbeitet. Setlength rausgeworfen und die Thread id mit in das array gepackt. Wenn der Thread durchgelaufen ist, wird die ID auf 0 gesetzt, und erscheint dann auch im memo nicht mehr. Kritik erwünscht !
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Comctrls, System.ImageList, Vcl.ImgList, Vcl.StdCtrls; type TmyThread = class(TThread) private fmeineThreadID: cardinal; public procedure Execute; override; procedure Synthreads; procedure Syni; property meineThreadID: Cardinal Read fmeineThreadID Write fmeineThreadID; end; TForm1 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; i:integer =0; var meinThread: array of TmyThread; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var i : integer; begin SetLength(meinthread, 20); for i := 0 to high(meinThread) do meinThread[i]:= TmyThread.Create(false); end; { TmyThread } procedure TmyThread.Execute; var z: integer; begin fmeineThreadID := ThreadID; SYNCHRONIZE(Self.Synthreads); for z := 0 to 50 do begin inc(i); sleep(random(500)); Synchronize(Syni); if Terminated then break; end; fmeineThreadID:= 0; Synchronize(Synthreads); FreeOnTerminate := true; end; procedure TmyThread.Syni; begin form1.Caption:= inttostr(i); end; procedure TmyThread.Synthreads; var line: integer; begin form1.memo1.clear; for line := Low(meinThread) to High(meinThread) do if meinThread[line].meineThreadID <> 0 then form1.Memo1.Lines.Add(inttostr(meinThread[line].ThreadID)); end; procedure TForm1.Button2Click(Sender: TObject); var i:integer; begin for I := 0 to high(meinThread) do if ((meinThread[i] <> nil ) and (meinThread[i].Terminated = false)) then meinThread[i].Terminate; end; end. |
AW: Delphi einfaches Multithread Beispiel.
Natürlich darf man Synchronize verwenden. Das ist dann wie ein Chef der die ganze Zeit über die Schulter schaut und sich dann beschwert, daß er sich um alles kümmern muß.Ein Thread ist erst dann sinnvoll wenn er "autark gedacht" wird. Wenn er länger läuft darf er messages versenden die dann vom Mainthread ausgewertet werden, das war es aber auch schon. Ist nicht ganz simpel aber machbar.
Gruß K-H |
AW: Delphi einfaches Multithread Beispiel.
Oje...
Ich werde keine Kritik schreiben - es ist noch kein Meister von Himmel gefallen...
Delphi-Quellcode:
Daher: Meine CodeRage2020 Session: Threads & Queues...
for var i:=0 to 19 do
TTask.Run() |
AW: Delphi einfaches Multithread Beispiel.
Frage dazu, weil ich es nicht sicher weiß, aber sehr stark "nein" vermute:
Darf man auf eine globale Integer-Variable (hier: i) von mehreren Threads aus einfach so per inc(i) zugreifen? Ist Inc wirklich atomar, oder müsste das nicht auch abgesichert werden (InterlockedIncrement, AtomicIncrement, CriticalSection, whatever?) |
AW: Delphi einfaches Multithread Beispiel.
Ja, Nein, ist es nicht. :stupid:
Delphi-Quellcode:
im Assembler ist nicht thread-safe, allerdings
INC x
Delphi-Quellcode:
ist es,
LOCK INC x
aber niemand will nur deswegen mit Assembler rumpfuschen, darum ![]() Die Lesezugriffe, ohne zusätzliche Absicherung, sind es damit dann auch. Falls man den Wert aber mehrmals (z.B. der IF dann nochmal) verwenden will, dann sollte man sich den Wert einmal kopieren (nur ein Zugriff und dann unveränderliche Kopie). |
AW: Delphi einfaches Multithread Beispiel.
Eigentlich müsste man den kompletten Code streichen und ersetzen. Kein Anfänger oder überhaupt jemand sollte sich ein beispiel daran nehmen.
Ich empfehle hier zumindestest ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:55 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz