Cititorii ca tine ajută la sprijinirea MUO. Când efectuați o achiziție folosind link-uri de pe site-ul nostru, este posibil să câștigăm un comision de afiliat. Citeşte mai mult.

Pe Linux, puteți crea și gestiona fire de execuție în C/C++ folosind biblioteca POSIX thread (pthread). Spre deosebire de alte sisteme de operare, există o mică diferență între un fir și un proces în Linux. De aceea, Linux se referă adesea la firele sale ca fiind procese ușoare.

Folosind biblioteca pthread, puteți crea fire de execuție, puteți aștepta ca acestea să se termine și le puteți termina în mod explicit.

Istoria utilizării thread-urilor pe Linux

Înainte de versiunea Linux 2.6, implementarea principală a firului de execuție era LinuxThreads. Această implementare a avut limite semnificative în ceea ce privește performanța și operațiunile de sincronizare. O limită a numărului maxim de fire de execuție care puteau rula le-a limitat în anii 1000.

În 2003, o echipă condusă de dezvoltatori de la IBM și RedHat a reușit să realizeze

instagram viewer
Biblioteca nativă de fire POSIX (NPTL) proiect disponibil. A fost introdus pentru prima dată în RedHat Enterprise versiunea 3 pentru a rezolva problemele de performanță cu Java Virtual Machine pe Linux. Astăzi, biblioteca GNU C conține implementări ale ambelor mecanisme de threading.

Niciuna dintre acestea nu este o implementare de fire verzi, pe care o mașină virtuală le-ar gestiona și rula în modul pur utilizator. Când utilizați biblioteca pthread, nucleul creează un fir de execuție de fiecare dată când pornește un program.

Puteți găsi informații specifice firului pentru orice proces care rulează în fișierele de sub /proc//task. Aceasta este locația standard pentru informațiile de proces sub standardul procfs Linux. Pentru aplicațiile cu un singur fir, va apărea că în acest director există o înregistrare de activitate cu aceeași valoare ca PID-ul.

Logica de lucru a firelor

Threadurile sunt ca procesele care rulează în prezent pe sistemul de operare. În sistemele cu un singur procesor (de exemplu, microcontrolere), nucleul sistemului de operare simulează fire. Acest lucru permite tranzacțiilor să ruleze simultan prin tăiere.

Un sistem de operare cu un singur nucleu poate rula cu adevărat doar un proces la un moment dat. Cu toate acestea, în sisteme multi-core sau multi-procesor, aceste procese pot rula simultan.

Crearea firului în C

Puteți folosi pthread_create funcția de a crea un fir nou. The pthread.h fișierul antet include definiția semnăturii sale împreună cu alte funcții legate de fire. Threadurile folosesc același spațiu de adrese și descriptori de fișiere ca și programul principal.

Biblioteca pthread include, de asemenea, suportul necesar pentru operațiile mutex și condiționate necesare pentru operațiunile de sincronizare.

Când utilizați funcțiile bibliotecii pthread, trebuie să vă asigurați că compilatorul leagă pthread bibliotecă în executabilul dvs. Dacă este necesar, puteți solicita compilatorului să facă legătura la bibliotecă folosind -l opțiune:

gcc -o Test test_thread.c -lpthread

Funcția pthread_create are următoarea semnătură:

intpthread_create(pthread_t *fir, constpthread_attr_t *attr, gol *(*start_rutine)(gol *), gol *arg)

Returnează 0 dacă procedura are succes. Dacă există o problemă, returnează un cod de eroare diferit de zero. În semnătura funcției de mai sus:

  • The fir parametrul este de tip pthread_t. Firul creat va fi întotdeauna accesibil cu această referință.
  • The attr parametrul vă permite să specificați un comportament personalizat. Puteți utiliza o serie de funcții specifice firului, începând cu pthread_attr_ pentru a seta această valoare. Personalizările posibile sunt politica de programare, dimensiunea stivei și politica de detașare.
  • start_rutine specifică funcția pe care o va rula firul.
  • arg reprezintă o structură de date generică transmisă funcției de către thread.

Iată un exemplu de aplicație:

#include
#include
#include
#include

gol *muncitor(gol *date)
{
char *nume = (char*)date;

pentru (int i = 0; eu < 120; i++)
{
tu dormi(50000);
printf("Salut de la numele firului = %s\n", nume);
}

printf(„Fila %s gata!\n”, nume);
întoarcereNUL;
}

intprincipal(gol)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, muncitor, „X”);
pthread_create(&th2, NUL, muncitor, „Y”);
dormi(5);
printf("Ieșire din programul principal\n");
întoarcere0;
}

Tipuri de fire

Când un fir se întoarce din principal() într-o aplicație, toate firele de execuție se termină și sistemul eliberează toate resursele utilizate de program. La fel, la ieșirea din orice fir cu o comandă precum an Ieșire(), programul dvs. va termina toate firele.

Cu pthread_join funcție, puteți aștepta ca un fir să se termine. Firul care utilizează această funcție se va bloca până când firul așteptat se termină. Resursele pe care le folosesc din sistem nu sunt returnate nici măcar în cazuri precum terminarea firelor de execuție care se pot alătura, neprogramată de CPU sau chiar eșecul de a se alătura cu ptread_join.

Uneori există situații în care alăturarea cu pthread_join nu are sens; dacă este imposibil de prezis când se va termina firul, de exemplu. În acest caz, vă puteți asigura că sistemul returnează automat toate resursele în punctul în care se întoarce firul.

Pentru a realiza acest lucru, ar trebui să începeți firele relevante cu DETAȘAT stare. Când începeți un thread, DESPRINDE starea poate fi setată prin valorile atributelor unui fir sau cu ajutorul pthread_detach funcţie:

intpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
intpthread_detach(pthread_t fir);

Iată un exemplu de utilizare a pthread_join(). Înlocuiți funcția principală din primul program cu următoarele:

intprincipal(gol)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, muncitor, „X”);
pthread_create(&th2, NUL, muncitor, „Y”);
dormi(5);
printf(„ieșire din programul principal\n”);
pthread_join (th1, NUL);
pthread_join (th2, NUL);
întoarcere0;
}

Când compilați și rulați programul, rezultatul dvs. va fi:

Salut din threadul Y
Salut din threadul X
Salut din threadul Y
...
Salut din threadul Y
ieșirea din programul principal
Salut din threadul X
...
Salut din threadul X
Thread X gata!
Salut din threadul Y
Firul Y gata!

Terminarea firului

Puteți anula un fir cu un apel la pthread_cancel, trecându-l corespunzător pthread_t id:

intpthread_cancel(pthread_t fir);

Puteți vedea acest lucru în acțiune în următorul cod. Din nou, doar principal functia este diferita:

intprincipal(gol)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, muncitor, „X”);
pthread_create(&th2, NUL, muncitor, „Y”);
dormi(1);
printf("> Anularea firului Y!!\n");
pthread_cancel (th2);
tu dormi(100000);
printf("> Anularea Thread X!\n");
pthread_cancel (th1);
printf(„ieșire din programul principal\n”);
întoarcere0;
}

De ce sunt create firele?

Sistemele de operare încearcă întotdeauna să ruleze fire pe unul sau mai multe procesoare, fie dintr-o listă creată de sine, fie dintr-o listă de fire creată de utilizator. Unele fire nu pot rula deoarece așteaptă un semnal de intrare/ieșire de la hardware. Ei pot, de asemenea, să aştepte voluntar, să aştepte un răspuns de la un alt thread sau să aibă un alt thread care îi blochează.

Puteți ajusta resursele pe care le alocați firelor pe care le creați folosind pthread. Aceasta poate fi o politică de programare personalizată sau puteți alege algoritmi de programare, cum ar fi FIFO sau Round-robin, dacă doriți.