Dezvoltarea aplicațiilor multithreaded în constructorul c

Dezvoltarea de aplicații multi-threaded în C ++ Builder

C ++ Builder oferă mai multe obiecte care ușurează dezvoltarea aplicațiilor cu mai multe filete.






Pentru a crea aplicații multi-threaded în C ++ Builder, este implementată clasa abstractă TThread.
TThread este o clasă abstractă care permite crearea de fire separate care rulează în aplicație.
Creați un descendent al clasei TThread pentru a reprezenta firul executabil într-o aplicație cu mai multe fire.
Fiecare nouă instanță a copilului TThread este un fir nou de execuție.
Setul de instanțe primite din clasa TThread. face C ++ Builder o aplicație multi-threaded.

Trebuie să creați un obiect de clasă nou derivat din TThread.
Pentru a face acest lucru:

Selectați Fișier | Nou | Altele | Obiectul subiectului. Pentru a crea un nou modul care conține un obiect derivat din clasa TThread,
vi se va cere să sunați cumva această clasă, să o numiți după cum doriți (de ex. TMyThread)
Se va crea un nou modul care conține o descriere a acestei clase TMyThread, a constructorului acesteia și a metodei Execute ().

În programul principal, creați un obiect al acestei clase de fluxuri
// creați firul într-o stare suspendată (adevărat), execută (fals)

TMyThread * Thr = nou TMyThread (adevărat); // în pauză

Dacă observați, în constructor există un parametru bool CreateSuspended. dacă creați
Acest parametru este setat la fals. fluxul dintr-o dată - când obiectul este creat, acesta își va începe activitatea,
adică executarea codului în metoda Execute () va începe, dacă parametrul bool CreateSuspended este adevărat. va fi creat
thread într-o stare suspendată, trebuie să utilizați metoda Resume () pentru a porni firul
Thr-> Reluare ();

De asemenea, de exemplu, în constructor, puteți specifica (modifica) prioritatea firului - adică, cât timp CPU-ul este necesar
va aloca un sistem de operare pentru firul dvs., în raport cu celelalte fire ale aplicației dvs.
- Proprietatea prioritară este responsabilă pentru acest lucru. Implicit, toate firele sunt create cu prioritate normală.

Thr-> Prioritate = tpLower; // setați prioritatea mai mică decât cea normală
Thr-> Reluare (); // începe execuția firului

Prioritățile pot avea următoarele valori:

firul primește cea mai mare prioritate

Puteți suspenda firul folosind metoda Suspend (). executați firul cu metoda Resume ()
Firele sunt terminate automat când funcția Execute () este finalizată sau aplicația este închisă.

Pentru a face memoria liberă fără fir atunci când firul se termină, utilizați în Execute () FreeOnTerminate = true;
Cu toate acestea, pot exista situații în care finalizarea fluxului trebuie coordonată cu alt fir. De exemplu, ar trebui să așteptați valoarea returnată dintr-un fir pentru a returna această valoare unui alt fir. Pentru a face acest lucru, nu eliberați primul fir până când cel de-al doilea fir primește valoarea returnată. Puteți rezolva această situație setând FreeOnTerminate = false și apoi eliberând în mod explicit primul fir din al doilea.

Pentru a opri executarea unui fir fără a aștepta finalizarea acestuia, de exemplu dintr-un alt fir, utilizați metoda Terminate ().
Thr-> Terminare ();
Metoda Terminate () setează true pentru proprietatea Terminated. adică, trebuie să curgeți
(în metoda Execute) verificați periodic valoarea terminată și dacă această valoare este adevărată,
să ia măsurile necesare, de exemplu, pentru a finaliza fluxul, adică ieșire executați ()
De exemplu,

void __fastcall TMyThread :: Execute ()
FreeOnTerminate = true; // eliberați memoria ocupată de fir la sfârșitul lucrului
pentru (int i = 0; i<10000; i++)
- - unele calcule complicate în bucla
dacă se întrerupe (terminat); // anulați - firul complet
>
>

În situații extreme, pentru a termina fluxul, utilizați API-ul TerminateThread ().
Această funcție închide firul curent fără a elibera memoria ocupată de firul de proces.
Sintaxa lui: TerminateThread ((HANDLE) Thr-> Handle, false);

Acum, despre particularitățile fluxurilor de lucru în aplicațiile C ++ Builder (bibliotecă VCL)

După cum știți când scrieți programe în C ++ Builder (și Delphi), utilizați de obicei biblioteca VCL.
(de exemplu, componente din paleta de componente)
Când folosiți obiecte din ierarhiile VCL sau CLX, proprietățile și metodele lor, siguranța firului nu este garantată.
Adică prin accesarea proprietăților sau prin efectuarea metodelor acestor obiecte, pot fi efectuate anumite acțiuni care utilizează memorie care nu este protejată de acțiunile altor fire.
Deci, fluxul principal al bibliotecii VCL ar trebui să fie singurul fir care gestionează această bibliotecă.






(este, de asemenea, fluxul primar al aplicației dvs.)
Ea procesează toate mesajele Windows primite de componente în aplicația dvs.
Cum, deci, este sigur să obținem controlul asupra proprietăților și metodelor obiectelor (componentelor) VCL din fir?
Pentru aceasta, TThread are o metodă Synchronize ()

void __fastcall TMyThread :: Execute ()
FreeOnTerminate = true; // eliberați memoria ocupată de fir la sfârșitul lucrului
pentru (int i = 0; i<10000; i++)
- - unele calcule complicate în bucla
// ---
dacă se întrerupe (terminat); // opriți fluxul din afară
Sincronizați (pb); // permite accesul la proprietățile și metodele obiectelor VCL
>
>
// ------------------------------------------------ ---------------------------

void __fastcall TMyThread :: pb ()
static int n = 0;

n ++;
Form1-> Label1-> Caption = n;
Aplicație-> Mesaje de proces ();
>
// -----


Fiți atenți. Deoarece sincronizarea utilizează o buclă de mesaje, aceasta nu funcționează în aplicațiile consolei. Trebuie să utilizați alte mecanisme, cum ar fi partițiile critice, pentru a proteja accesul la obiecte VCL sau CLX în aplicațiile console

Nu utilizați metoda de sincronizare pentru următoarele obiecte:
  • Componentele pentru accesul la date sunt în condiții de siguranță după cum urmează: Pentru seturile de date accesibile BDE, fiecare fir trebuie să aibă propria componentă de sesiune de bază de date. O excepție la aceasta este atunci când utilizați drivere Microsoft Access. care sunt generate utilizând o bibliotecă Microsoft care nu este sigură în legătură cu firul. Pentru dbDirect. În timp ce biblioteca client este thread-safe, componentele dbDirect vor fi în condiții de siguranță.
    Componentele ADO și InterbaseExpress sunt compatibile cu firul.
    Când utilizați accesul la date în fluxurile componentelor, trebuie să fiți mai atenți.
    De exemplu, trebuie să suni Synchronize, care leagă controlul datelor de setul de date. setarea proprietății DataSet a obiectului sursă de date. dar nu trebuie să utilizați Sincronizare pentru a accesa câmpul de date din setul de date.
    Pentru informații detaliate despre utilizarea sesiunilor de baze de date cu fire în aplicațiile cu funcții BDE, consultați Gestionarea mai multor sesiuni în Ajutor pentru C ++ Builder.
  • Obiectele DataCLX sunt thread-safe, deși obiectele VisualCLX nu sunt.
  • Obiectele grafice sunt sigure pentru fir. Nu aveți nevoie să utilizați fluxul principal VCL sau CLX pentru a accesa TFont, TPen, TBrush, TBitmap, TMetafile (numai VCL), TDrawing (numai CLX) sau TIcon. Obiectele Canvas pot fi folosite în afara metodei Sincronizare, trebuie doar să le blocați înainte de a aplica și elibera după,
    pentru aceasta, sunt utilizate metodele Lock () și Unlock (). de exemplu:
    // ---
    Form1-> Canvas-> Blocare ();
    pentru (int i = 0; i<5000; i++) Form1->Canvas-> TextOut (20,20, i);
    Form1-> Canvas-> Deblocare ();
    // ---
  • În timp ce obiectele din listă nu sunt protejate prin fir,
    Puteți utiliza versiunea sigură a fișierelor, TThreadList. în loc de TList.

În plus față de coordonarea activității firelor cu priorități de fir, adesea este adesea necesar să se sincronizeze firele. Ce se înțelege prin.
Coordonarea activității comune a mai multor fire, în cazul în care încearcă, de exemplu, să facă ceva în același timp,
de exemplu, pentru a afișa ceva pe formular, acces la date globale și așa mai departe.
Pentru a face acest lucru, utilizați obiecte precum secțiuni critice, mutexuri,
semafor, cronometre.

Secțiuni critice. (secțiune critică)

Pentru a crea și utiliza o secțiune critică, trebuie să declarați o variabilă de tip CRITICAL_SECTION,
în exemplul nostru din Unit1.h
.
public: // Declarații de utilizator
CRITICAL_SECTION CS;
.

// Atunci această variabilă CS trebuie inițializată (creați o partiție critică)
__fastcall TForm1 :: TForm1 (Proprietar TComponent *)
. TForm (Proprietar)
InitializeCriticalSection (CS);
>

// utilizați secțiunea critică din flux atunci când trebuie să blocați accesul la date
void __fastcall TMyThread :: Execute ()
FreeOnTerminate = true; // eliberați memoria ocupată de fir la sfârșitul lucrului
pentru (int i = 0; i<10000; i++)
- - unele calcule complicate în bucla
dacă se întrerupe (terminat); // opriți fluxul din afară
EnterCriticalSection (Form1-> CS); // blocați accesul la date (introduceți secțiunea critică)
. acces la date globale
LeaveCriticalSection (Form1-> CS); // închideți secțiunea critică (părăsiți secțiunea critică)
>
>

Când partiția critică nu este necesară, o ștergem
void __fastcall TForm1 :: FormClose (TObject * Expeditor, TCloseAction Acțiune)
DeleteCriticalSection (CS); // eliminați secțiunea critică
>

Mutexurile se execută mai încet decât secțiunile critice, dar au capacități mari,
decât secțiunile critice. De exemplu, ele pot fi utilizate de diferite procese.
Acestea sunt create folosind funcția API CreateMutex (). Lucrați cu ei este, de asemenea, realizat cu ajutorul lui
Funcțiile API, cum ar fi WaitForSingleObject (), ReleaseMutex (), etc.
Pentru informații despre utilizarea mutexelor și semaforilor, consultați Dezvoltarea aplicațiilor cu mai multe fire în Windows.

Descrierea clasei TThread (Situată în Classes.hpp)

clasa DELPHICLASS TThread;
clasa PASCALIMPLEMENTATION TThread. sistem public :: TObject
sistem typedef :: TObject moștenit;

privat:
nesignificat FHandle;
semn FThreadID nesemnate;
bool FCreateSuspendat;
bool FTerminated;
bool FS suspendat;
bool FFreeOnTerminate;
bool FFinished;
int FReturnValue;
TNotifyEvent FOnTerminate;
TThreadMethod FMethod;
Sistem :: TObject * FSynchronizeException;
Sistem :: TObject * FFatalException;
void __fastcall CheckThreadError (int ErrCode) / * suprasarcină * /;
void __fastcall CheckThreadError (bool Success) / * supraîncărcare * /;
void __fastcall CallOnTerminate (void);
TThreadPrioritate __fastcall GetPriority (void);
void __fastcall SetPriority (valoarea TThreadPrioritate);
void __fastcall Set Suspendat (valoare bool);

protejate:
virtual void __fastcall DoTerminate (vid);
virtual void __fastcall Executa (void) = 0;
void __fastcall Sincronizați (metoda TThreadMethod);
__property int ReturnValue =;
__property bool Terminat =;

publice:
__fastcall TThread (bool CreateSuspended);
__fastcall virtual

TThread (void);
virtual void __fastcall După construcție (void);
void __fastcall Reluare (vid);
void __fastcall Suspend (gol);
void __fastcall Terminare (vid);
nesemnate __fastcall WaitFor (void);
Sistem __property :: TObject * FatalException =;
__property bool FreeOnTerminate =;
__ Manevra nesemnată de referință =;
__property TThreadPrioritate Priority =;
__property bool Suspendat =;
__property nesemnate ThreadID =;
__property TNotifyEvent OnTerminate =;
>;


Proprietățile și metodele de bază ale clasei TThread







Articole similare

Trimiteți-le prietenilor: