Synkronisera trådar och GUI i en Delphi-applikation

Med flertrådar i Delphi kan du skapa applikationer som innehåller flera samtidiga sökvägar.

En normal Delphi-applikation är enkeltrådad, vilket innebär att alla VCL-objekt får åtkomst till deras egenskaper och kör sina metoder inom den här enstaka tråden. För att påskynda databehandlingen i din applikation, inkludera en eller flera sekundära trådar.

Processortrådar

EN tråd är en kommunikationskanal från en applikation till en processor. Enkeltrådiga program behöver kommunikation för att flöda i båda riktningarna (till och från processorn) när den körs; flera trådade appar kan öppna flera olika kanaler, vilket påskyndar körningen.

Trådar och GUI

När flera trådar körs i applikationen uppstår frågan hur du kan uppdatera ditt grafiska användargränssnitt som ett resultat av en trådkörning. Svaret ligger i klassen TThread Synkronisera metod.

För att uppdatera applikationens användargränssnitt eller huvudtråd från en sekundär tråd måste du anropa synkroniseringsmetoden. Den här tekniken är en trådsäker metod som undviker konflikter med flera trådar som kan uppstå genom att få tillgång till objektegenskaper eller metoder som inte är trådsäkra eller använda resurser som inte är i huvudtråden för körning.

Nedan följer ett exempel på en demo som använder flera knappar med framstegsfält, varvid varje framstegsfält visar det aktuella "tillståndet" för trådutförandet.

enhet MainU;
gränssnitt
användningar
Windows, meddelanden, SysUtils, varianter, klasser, grafik, kontroller, formulär,
Dialoger, ComCtrls, StdCtrls, ExtCtrls;
typ
// interceptor klass
TButton = klass (StdCtrls.TButton)
OwnedThread: TThread;
ProgressBar: TProgressBar;
slutet;
TMyThread = klass (TThread)
privat
FCounter: Heltal;
FCountTo: Heltal;
FProgressBar: TProgressBar;
FOwnerButton: TButton;
procedur DoProgress;
procedur SetCountTo (konstvärde: heltal);
procedur SetProgressBar (konstvärde: TProgressBar);
procedur SetOwnerButton (konstvärde: TButton);
skyddade
procedur Utför; åsidosätta;
offentlig
konstruktör Skapa (CreateSuspended: Boolean);
egenskap CountTo: Heltal läst FCountTo skriva SetCountTo;
egenskap ProgressBar: TProgressBar läs FProgressBar skriva SetProgressBar;
fastighetsägareButton: TButton läste FOwnerButton skriva SetOwnerButton;
slutet;
TMainForm = klass (TForm)
Knapp1: TButton;
ProgressBar1: TProgressBar;
Knapp2: TButton;
ProgressBar2: TProgressBar;
Knapp3: TButton;
ProgressBar3: TProgressBar;
Knapp4: TButton;
ProgressBar4: TProgressBar;
Knapp5: TButton;
ProgressBar5: TProgressBar;
procedur Knapp1Klicka (avsändare: TObject);
slutet;
var
MainForm: TMainForm;
genomförande
$ R * .dfm
TMyThread
konstruktör TMyThread.Create (CreateSuspended: Boolean);
Börja
ärvt;
FCounter: = 0;
FCountTo: = MAXINT;
slutet;
procedur TMyThread.DoProgress;
var
PctDone: Utökad;
Börja
PctDone: = (FCounter / FCountTo);
FProgressBar.Position: = Round (FProgressBar.Step * PctDone);
FOwnerButton.Caption: = FormatFloat ('0,00%', PctDone * 100);
slutet;
procedur TMyThread.Execute;
const
Intervall = 1000000;
Börja
FreeOnTerminate: = Sant;
FProgressBar.Max: = FCountTo div intervall;
FProgressBar.Step: = FProgressBar.Max;
medan FCounter < FCountTo do
Börja
om FCounter mod Interval = 0, synkronisera (DoProgress);
Inc (FCounter);
slutet;
FOwnerButton.Caption: = 'Start';
FOwnerButton.OwnedThread: = noll;
FProgressBar.Position: = FProgressBar.Max;
slutet;
procedur TMyThread.SetCountTo (const-värde: heltal);
Börja
FCountTo: = värde;
slutet;
procedur TMyThread.SetOwnerButton (konstvärde: TButton);
Börja
FOwnerButton: = värde;
slutet;
procedur TMyThread.SetProgressBar (konstvärde: TProgressBar);
Börja
FProgressBar: = värde;
slutet;
procedur TMainForm.Button1Click (avsändare: TObject);
var
aKnapp: TButton;
aThread: TMyThread;
aProgressBar: TProgressBar;
Börja
aButton: = TButton (avsändare);
om inte Tilldelad (aButton.OwnedThread) då
Börja
aThread: = TMyThread.Create (True);
aButton.OwnedThread: = aThread;
aProgressBar: = TProgressBar (FindComponent (StringReplace (aButton.Name, 'Button', 'ProgressBar', [])));
aThread.ProgressBar: = aProgressBar;
aThread.OwnerButton: = aButton;
aThread.Resume;
aButton.Caption: = 'Paus';
slutet
annan
Börja
om en knapp.OwnedThread.Susended sedan
aButton.OwnedThread.Resume
annan
aButton.OwnedThread.Suspend;
aButton.Caption: = 'Kör';
slutet;
slutet;
slutet.

Tack till Jens Borrisholt för att han skickat in detta kodprov.