Sincronizarea firelor și GUI într-o aplicație Delphi

Multi-thread în Delphi vă permite să creați aplicații care includ mai multe căi de execuție simultane.

O aplicație Delphi normală este cu un singur filet, ceea ce înseamnă că toate obiectele VCL își accesează proprietățile și își execută metodele în cadrul acestui singur thread. Pentru a accelera procesarea datelor din aplicația dvs., includeți unul sau mai multe fire secundare.

Fire de procesare

A fir este un canal de comunicare de la o aplicație la un procesor. Programele cu un singur fir au nevoie de comunicare pentru a curge în ambele direcții (către și dinspre procesor) pe măsură ce se execută; aplicațiile cu mai multe filete pot deschide mai multe canale diferite, accelerând astfel execuția.

Fire și GUI

Când rulează mai multe fire în aplicație, se pune întrebarea despre cum puteți actualiza interfața dvs. grafică de utilizator ca urmare a executării unui thread. Răspunsul se află în clasa TThread Sincroniza metodă.

Pentru a actualiza interfața de utilizare a aplicației sau thread-ul principal, dintr-un thread secundar, trebuie să apelați la metoda Sincronizare. Această tehnică este o metodă de tip thread-safe care evită conflictele de multi-threading care pot apărea din accesarea proprietăților obiectului sau a metodelor care nu sunt fire-safe sau folosind resurse care nu sunt în firul principal de execuție..

Mai jos este prezentat un exemplu de demo care folosește mai multe butoane cu bare de progres, fiecare bară de progres afișând „starea” actuală a execuției firului.

unitate MainU;
interfață
utilizări
Windows, mesaje, SysUtils, variante, clase, grafică, controale, formulare,
Dialoguri, ComCtrls, StdCtrls, ExtCtrls;
tip
// clasa de interceptor
TButton = clasă (StdCtrls.TButton)
OwnedThread: TThread;
ProgressBar: TProgressBar;
Sfârșit;
TMyThread = clasă (TThread)
privat
FCounter: Integer;
FCountTo: Integer;
FProgressBar: TProgressBar;
Butonul FOwner: TButton;
procedura DoProgress;
procedura SetCountTo (const Valoare: Integer);
procedura SetProgressBar (const Valoare: TProgressBar);
procedura SetOwnerButton (valoare constantă: TButton);
protejat
procedura Executa; trece peste;
public
constructor Create (CreateSuspended: Boolean);
Proprietatea CountTo: citire integrală FCountTo scrie SetCountTo;
Proprietatea ProgressBar: TProgressBar citește FProgressBar scrie SetProgressBar;
property OwnerButton: TButton citește FOwnerButton scrie SetOwnerButton;
Sfârșit;
TMainForm = clasă (TForm)
Buton1: TButton;
ProgressBar1: TProgressBar;
Buton2: TButton;
ProgressBar2: TProgressBar;
Butonul 3: TButton;
ProgressBar3: TProgressBar;
Buton 4: TButton;
ProgressBar4: TProgressBar;
Buton5: TButton;
ProgressBar5: TProgressBar;
procedura Button1Click (Expeditor: TObject);
Sfârșit;
var
MainForm: TMainForm;
punerea în aplicare
$ R * .dfm
TMyThread
constructor TMyThread.Create (CreateSuspendat: Boolean);
începe
mostenit;
FCounter: = 0;
FCountTo: = MAXINT;
Sfârșit;
procedura TMyThread.DoProgress;
var
PctDone: Extins;
începe
PctDone: = (FCounter / FCountTo);
FProgressBar.Position: = Round (FProgressBar.Step * PctDone);
FOwnerButton.Caption: = FormatFloat ('0,00%', PctDone * 100);
Sfârșit;
procedura TMyThread.Execute;
const
Interval = 1000000;
începe
FreeOnTerminate: = True;
FProgressBar.Max: = Intervalul FCountTo div;
FProgressBar.Step: = FProgressBar.Max;
în timp ce FCounter < FCountTo do
începe
dacă FCounter mod Interval = 0 atunci Sincronizați (DoProgress);
Inc (FCounter);
Sfârșit;
FOwnerButton.Caption: = 'Start';
FOwnerButton.OwnedThread: = nil;
FProgressBar.Position: = FProgressBar.Max;
Sfârșit;
procedura TMyThread.SetCountTo (const Valoare: Integer);
începe
FCountTo: = valoare;
Sfârșit;
procedura TMyThread.SetOwnerButton (valoare constantă: TButton);
începe
FOwnerButton: = valoare;
Sfârșit;
procedura TMyThread.SetProgressBar (const Valoare: TProgressBar);
începe
FProgressBar: = valoare;
Sfârșit;
procedura TMainForm.Button1Click (Expeditor: TObject);
var
aButton: TButton;
aThread: TMyThread;
aProgressBar: TProgressBar;
începe
aButton: = TButton (Expeditor);
dacă nu este Atribuit (aButton.OwnedThread) atunci
începe
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: = 'Pauză';
Sfârșit
altfel
începe
dacă aButton.OwnedThread.Suspended atunci
aButton.OwnedThread.Resume
altfel
aButton.OwnedThread.Suspend;
aButton.Caption: = 'Rulați';
Sfârșit;
Sfârșit;
Sfârșit.

Mulțumim lui Jens Borrisholt pentru trimiterea acestui eșantion de cod.