Lezers zoals jij steunen MUO. Wanneer u een aankoop doet via links op onze site, kunnen we een aangesloten commissie verdienen. Lees verder.

Op Linux kunt u threads maken en beheren in C/C++ met behulp van de POSIX-threadbibliotheek (pthread). In tegenstelling tot andere besturingssystemen is er weinig verschil tussen een thread en een proces in Linux. Daarom verwijst Linux vaak naar zijn threads als lichtgewicht processen.

Met behulp van de pthread-bibliotheek kunt u threads maken, wachten tot ze eindigen en ze expliciet beëindigen.

De geschiedenis van threadgebruik op Linux

Vóór Linux-versie 2.6 was LinuxThreads de belangrijkste thread-implementatie. Deze implementatie had aanzienlijke beperkingen op het gebied van prestaties en synchronisatiebewerkingen. Een limiet op het maximale aantal threads dat kon worden uitgevoerd, beperkte ze tot in de 1000s.

In 2003 slaagde een team onder leiding van ontwikkelaars van IBM en RedHat erin om de Native POSIX-threadbibliotheek (NPTL) project beschikbaar. Het werd voor het eerst geïntroduceerd in RedHat Enterprise versie 3 om prestatieproblemen met de Java Virtual Machine op Linux op te lossen. Tegenwoordig bevat de GNU C-bibliotheek implementaties van beide threading-mechanismen.

instagram viewer

Geen van beide is een implementatie van groene threads, die een virtuele machine zou beheren en uitvoeren in puur gebruikersmodus. Als je de pthread-bibliotheek gebruikt, maakt de kernel een thread aan elke keer dat een programma start.

U kunt thread-specifieke informatie vinden voor elk lopend proces in de onderstaande bestanden /proc//task. Dit is de standaardlocatie voor procesinformatie onder de procfs Linux-standaard. Voor toepassingen met één thread lijkt het erop dat er een taakrecord is met dezelfde waarde als de PID onder deze map.

Werkende logica van threads

Threads zijn als processen die momenteel op het besturingssysteem worden uitgevoerd. In systemen met één processor (bijvoorbeeld microcontrollers) simuleert de kernel van het besturingssysteem threads. Hierdoor kunnen transacties gelijktijdig worden uitgevoerd door middel van slicing.

Een single-core besturingssysteem kan maar één proces tegelijk uitvoeren. Echter, binnen multi-core of multi-processor systemenkunnen deze processen gelijktijdig worden uitgevoerd.

Draad maken in C

U kunt de pthread_creëren functie om een ​​nieuwe thread aan te maken. De pthread.h header-bestand bevat de handtekeningdefinitie samen met andere threadgerelateerde functies. Threads gebruiken dezelfde adresruimte en bestandsbeschrijvingen als het hoofdprogramma.

De pthread-bibliotheek bevat ook de nodige ondersteuning voor mutex en voorwaardelijke bewerkingen die nodig zijn voor synchronisatiebewerkingen.

Wanneer u de functies van de pthread-bibliotheek gebruikt, moet u ervoor zorgen dat de compiler de draad bibliotheek in uw uitvoerbaar bestand. Indien nodig kunt u de compiler opdracht geven om naar de bibliotheek te linken met behulp van de -l keuze:

gcc -o test test_thread.c -lpthread

De functie pthread_create heeft de volgende handtekening:

intpthread_creëren(pthread_t *draad, constpthread_attr_t *attr, leegte *(*start_routine)(leegte *), leegte *arg)

Het retourneert 0 als de procedure succesvol is. Als er een probleem is, retourneert het een niet-nul foutcode. In de bovenstaande functiehandtekening:

  • De draad parameter is van het type pthread_t. De aangemaakte thread zal altijd toegankelijk zijn met deze referentie.
  • De atr parameter kunt u aangepast gedrag specificeren. U kunt een reeks threadspecifieke functies gebruiken, te beginnen met pthread_attr_ om deze waarde in te stellen. Mogelijke aanpassingen zijn het planningsbeleid, de stapelgrootte en het ontkoppelingsbeleid.
  • start_routine specificeert de functie die de thread zal uitvoeren.
  • arg vertegenwoordigt een generieke gegevensstructuur die door de thread aan de functie wordt doorgegeven.

Hier is een voorbeeldtoepassing:

#erbij betrekken
#erbij betrekken
#erbij betrekken
#erbij betrekken

leegte *arbeider(leegte *gegevens)
{
char *naam = (char*)gegevens;

voor (int ik = 0; ik < 120; ik++)
{
jij slaapt(50000);
printf("Hoi van threadnaam = %s\n", naam);
}

printf("Draad %s klaar!\n", naam);
opbrengstNUL;
}

intvoornaamst(leegte)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, arbeider, "X");
pthread_create(&th2, NUL, arbeider, "Y");
slaap(5);
printf("Verlaten van het hoofdprogramma\n");
opbrengst0;
}

Draadsoorten

Wanneer een thread terugkeert van de voornaamst() functie in een toepassing, eindigen alle threads en maakt het systeem alle bronnen vrij die het programma gebruikte. Evenzo, bij het afsluiten van een thread met een commando zoals een Uitgang(), beëindigt uw programma alle threads.

Met de pthread_join functie, kunt u in plaats daarvan wachten tot een thread is beëindigd. De thread die deze functie gebruikt, blokkeert totdat de verwachte thread eindigt. De bronnen die ze van het systeem gebruiken, worden niet teruggegeven, zelfs niet in gevallen zoals het beëindigen van samenvoegbare threads, ongepland door de CPU, of zelfs niet deelnemen aan ptread_join.

Soms zijn er situaties waarin meedoen met pthread_join geen zin heeft; als het bijvoorbeeld onmogelijk is om te voorspellen wanneer de thread zal eindigen. In dit geval kunt u ervoor zorgen dat het systeem alle bronnen automatisch retourneert op het punt waar de thread terugkeert.

Om dit te bereiken, moet u de relevante threads starten met de LOSGEMAAKT toestand. Bij het starten van een draad, ONTKOPPELEN status kan worden ingesteld via een threadattribuutwaarden of met de pthread_detach functie:

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

Hier is een voorbeeld van het gebruik van pthread_join(). Vervang de hoofdfunctie in het eerste programma door het volgende:

intvoornaamst(leegte)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, arbeider, "X");
pthread_create(&th2, NUL, arbeider, "Y");
slaap(5);
printf("het hoofdprogramma verlaten\n");
pthread_join (th1, NUL);
pthread_join (th2, NUL);
opbrengst0;
}

Wanneer u het programma compileert en uitvoert, is uw uitvoer:

Hallo uit topic Y
Hallo uit topic X
Hallo uit topic Y
...
Hallo uit topic Y
verlaten van het hoofdprogramma
Hallo uit topic X
...
Hallo uit topic X
Draad X klaar!
Hallo uit topic Y
Draad Y klaar!

Beëindiging van draad

U kunt een thread annuleren met een aanroep naar pthread_cancel, waarbij u het bijbehorende pthread_t ID kaart:

intpthread_cancel(pthread_t draad);

U kunt dit in actie zien in de volgende code. Nogmaals, alleen de voornaamst functie is anders:

intvoornaamst(leegte)
{
pthread_t th1, th2;
pthread_create(&th1, NUL, arbeider, "X");
pthread_create(&th2, NUL, arbeider, "Y");
slaap(1);
printf("> Discussie Y!!\n annuleren");
pthread_cancel (th2);
jij slaapt(100000);
printf("> Discussie X annuleren!\n");
pthread_cancel (th1);
printf("het hoofdprogramma verlaten\n");
opbrengst0;
}

Waarom worden threads gemaakt?

Besturingssystemen proberen altijd threads uit te voeren op een of meer CPU's, hetzij vanuit een zelf gemaakte lijst, hetzij vanuit een door de gebruiker gemaakte threadlijst. Sommige threads kunnen niet worden uitgevoerd omdat ze wachten op een invoer-/uitvoersignaal van de hardware. Ze kunnen ook vrijwillig wachten, wachten op een reactie van een andere thread, of een andere thread heeft hen geblokkeerd.

U kunt de bronnen aanpassen die u toewijst aan threads die u maakt met behulp van pthread. Dit kan een aangepast planningsbeleid zijn, of u kunt indien gewenst planningsalgoritmen zoals FIFO of Round-robin kiezen.