Introducere în multithreading - Clasa Thread
Unul dintre aspectele cheie în programarea modernă este multithreading-ul. Conceptul principal în lucrul cu multithreading-ul este thread-ul. Un thread reprezintă o parte din codul programului. La rularea programului, fiecărui thread i se alocă un anumit cuantum de timp.
Prin intermediul multithreading-ului, putem aloca în aplicație mai multe thread-uri care vor executa diverse sarcini simultan. Dacă avem, de exemplu, o aplicație grafică ce trimite o cerere către un server sau citește și procesează un fișier mare, fără multithreading, interfața grafică ar fi blocată pe durata executării sarcinii.
Datorită thread-urilor, putem aloca trimiterea cererii sau orice altă sarcină care necesită timp îndelungat unui thread separat. Astfel, de exemplu, aplicațiile client-server (și nu doar ele) sunt de neconceput fără multithreading.
Funcționalitatea principală pentru utilizarea thread-urilor într-o aplicație este concentrată în namespace-ul System.Threading. În acesta este definită clasa ce reprezintă un thread separat - clasa Thread.
Clasa Thread definește o serie de metode și proprietăți care permit gestionarea thread-ului și obținerea informațiilor despre acesta. Proprietățile principale ale clasei sunt:
- ExecutionContext: permite obținerea contextului în care se execută thread-ul
- IsAlive: indică dacă thread-ul rulează în prezent
- IsBackground: indică dacă thread-ul este de fundal
- Name: conține numele thread-ului
- ManagedThreadId: returnează identificatorul numeric al thread-ului curent
- Priority: stochează prioritatea thread-ului - valoarea unei enumerații ThreadPriority: Lowest BelowNormal Normal AboveNormal Highest
Implicit, unui thread i se atribuie valoarea Normal. Totuși, putem modifica prioritatea în timpul rulării programului. De exemplu, putem crește importanța thread-ului setând prioritatea Highest. Mediul CLR va citi și analiza valorile priorității și, pe baza acestora, va aloca thread-ului respectiv o anumită cantitate de timp.
- ThreadState returnează starea thread-ului - una dintre valorile enumerației ThreadState:
- Aborted: thread-ul este oprit, dar încă nu a fost finalizat
- AbortRequested: pentru thread a fost apelată metoda Abort, dar oprirea încă nu a avut loc
- Background: thread-ul rulează în mod de fundal
- Running: thread-ul este pornit și rulează (nu este suspendat)
- Stopped: thread-ul este finalizat
- StopRequested: thread-ul a primit o cerere de oprire
- Suspended: thread-ul este suspendat
- SuspendRequested: thread-ul a primit o cerere de suspendare
- Unstarted: thread-ul nu a fost încă pornit
- WaitSleepJoin: thread-ul este blocat în urma apelării metodelor Sleep sau Join
În timpul rulării thread-ului, starea acestuia poate fi modificată de mai multe ori prin intermediul metodelor. De exemplu, la început, înainte de aplicarea metodei Start, starea este Unstarted. După pornirea thread-ului, starea se schimbă în Running. Apelând metoda Sleep, starea se va schimba în WaitSleepJoin.
În plus, proprietatea statică CurrentThread a clasei Thread permite obținerea thread-ului curent.
Într-un program C#, există cel puțin un thread - thread-ul principal, în care se execută metoda Main.
De exemplu, utilizăm proprietățile descrise mai sus pentru a obține informații despre thread:
using System.Threading;
// obținem thread-ul curent
Thread currentThread = Thread.CurrentThread;
// obținem numele thread-ului
Console.WriteLine($"Numele thread-ului: {currentThread.Name}");
currentThread.Name = "Metoda Main";
Console.WriteLine($"Numele thread-ului: {currentThread.Name}");
Console.WriteLine($"Thread-ul este pornit: {currentThread.IsAlive}");
Console.WriteLine($"Id-ul thread-ului: {currentThread.ManagedThreadId}");
Console.WriteLine($"Prioritatea thread-ului: {currentThread.Priority}");
Console.WriteLine($"Starea thread-ului: {currentThread.ThreadState}");
În acest caz, vom obține aproximativ următorul output:
Numele thread-ului:
Numele thread-ului: Metoda Main
Thread-ul este pornit: True
Id-ul thread-ului: 1
Prioritatea thread-ului: Normal
Starea thread-ului: Running
Deoarece implicit, proprietatea Name a obiectelor Thread nu este setată, în primul caz vom obține o valoare de șir gol pentru această proprietate.
De asemenea, clasa Thread definește o serie de metode pentru gestionarea thread-urilor. Principalele dintre acestea sunt:
- Metoda statică GetDomain returnează o referință la domeniul aplicației
- Metoda statică GetDomainID returnează id-ul domeniului aplicației în care se execută thread-ul curent
- Metoda statică Sleep oprește thread-ul pentru un anumit număr de milisecunde
- Metoda Interrupt întrerupe thread-ul aflat în starea WaitSleepJoin
- Metoda Join blochează execuția thread-ului care a apelat această metodă până când se finalizează thread-ul pentru care a fost apelată metoda
- Metoda Start pornește thread-ul
De exemplu, utilizăm metoda Sleep pentru a seta o întârziere în execuția aplicației:
using System.Threading;
for(int i = 0; i < 10; i++)
{
Thread.Sleep(500); // întârziere în execuție de 500 de milisecunde
Console.WriteLine(i);
}