V systéme Linux môžete vytvárať a spravovať vlákna v C/C++ pomocou knižnice vlákien POSIX (pthread). Na rozdiel od iných operačných systémov je v Linuxe malý rozdiel medzi vláknom a procesom. To je dôvod, prečo Linux často označuje svoje vlákna ako ľahké procesy.
Pomocou knižnice pthread môžete vytvárať vlákna, čakať na ich ukončenie a explicitne ich ukončiť.
História používania vlákien v systéme Linux
Pred verziou Linuxu 2.6 bola implementácia hlavného vlákna LinuxThreads. Táto implementácia mala značné limity z hľadiska výkonu a synchronizačných operácií. Obmedzenie maximálneho počtu vlákien, ktoré bolo možné spustiť, ich obmedzilo na 1000.
V roku 2003 sa tímu pod vedením vývojárov z IBM a RedHat podarilo vytvoriť Natívna knižnica vlákien POSIX (NPTL) projekt k dispozícii. Prvýkrát bol predstavený vo verzii RedHat Enterprise 3 na riešenie problémov s výkonom Java Virtual Machine v systéme Linux. Knižnica GNU C dnes obsahuje implementácie oboch mechanizmov vlákna.
Ani jedno z toho nie je implementáciou zelených vlákien, ktoré by virtuálny stroj spravoval a spúšťal v čisto užívateľskom režime. Keď použijete knižnicu pthread, jadro vytvorí vlákno pri každom spustení programu.
Informácie špecifické pre vlákna pre každý spustený proces nájdete v súboroch pod /proc/
Pracovná logika vlákien
Vlákna sú ako procesy, ktoré momentálne bežia v operačnom systéme. V jednoprocesorových systémoch (napr. mikrokontroléry) jadro operačného systému simuluje vlákna. To umožňuje, aby transakcie prebiehali súčasne prostredníctvom krájania.
Jednojadrový operačný systém môže skutočne spustiť iba jeden proces súčasne. Avšak v viacjadrové alebo viacprocesorové systémy, tieto procesy môžu prebiehať súčasne.
Vytvorenie vlákna v C
Môžete použiť pthread_create funkcia na vytvorenie nového vlákna. The pthread.h hlavičkový súbor obsahuje definíciu podpisu spolu s ďalšími funkciami súvisiacimi s vláknami. Vlákna používajú rovnaký adresný priestor a deskriptory súborov ako hlavný program.
Knižnica pthread obsahuje aj potrebnú podporu pre mutex a podmienené operácie potrebné pre synchronizačné operácie.
Keď používate funkcie knižnice pthread, musíte zabezpečiť, aby kompilátor prepojil s pthread knižnice do spustiteľného súboru. Ak je to potrebné, môžete dať kompilátoru pokyn, aby sa prepojil s knižnicou pomocou -l možnosť:
gcc -o test test_thread.c -lpthread
Funkcia pthread_create má nasledujúci podpis:
intpthread_create(pthread_t *vlákno, konštpthread_attr_t *attr, neplatné *(*start_routine)(neplatné *), neplatné *arg)
Ak je postup úspešný, vráti 0. Ak sa vyskytne problém, vráti nenulový kód chyby. Vo vyššie uvedenom podpise funkcie:
- The niť parameter je typu pthread_t. Vytvorené vlákno bude vždy prístupné s týmto odkazom.
- The attr parameter vám umožňuje špecifikovať vlastné správanie. Môžete použiť sériu funkcií špecifických pre vlákna počnúc pthread_attr_ na nastavenie tejto hodnoty. Možné prispôsobenia sú politika plánovania, veľkosť zásobníka a politika odpojenia.
- štart_rutina určuje funkciu, ktorú vlákno spustí.
- arg predstavuje všeobecnú dátovú štruktúru odovzdanú funkcii vláknom.
Tu je príklad aplikácie:
#zahŕňajú
#zahŕňajú
#zahŕňajú
#zahŕňajúneplatné *pracovník(neplatné *údaje)
{
char *meno = (char*) údaje;
pre (int i = 0; ja < 120; i++)
{
spať (50000);
printf("Ahoj z názvu vlákna = %s\n", meno);
}
printf("Vlákno %s hotové!\n", názov);
vrátiťNULOVÝ;
}
intHlavná(neplatné)
{
pthread_t th1, th2;
pthread_create(&th1, NULOVÝ, pracovník, "X");
pthread_create(&th2, NULOVÝ, pracovník, "Y");
spať (5);
printf("Ukončenie hlavného programu\n");
vrátiť0;
}
Typy vlákien
Keď sa vlákno vráti z Hlavná() všetky vlákna sa ukončia a systém uvoľní všetky zdroje, ktoré program použil. Podobne pri opúšťaní ľubovoľného vlákna pomocou príkazu ako an VÝCHOD(), váš program ukončí všetky vlákna.
S pthread_join namiesto toho môžete počkať na ukončenie vlákna. Vlákno používajúce túto funkciu sa zablokuje, kým sa neskončí očakávané vlákno. Zdroje, ktoré používajú zo systému, sa nevracajú ani v prípadoch, ako je ukončenie spájateľných vlákien, neplánované CPU alebo dokonca zlyhanie spojenia s ptread_join.
Niekedy nastanú situácie, keď spojenie s pthread_join nedáva zmysel; ak nie je možné predpovedať, kedy sa vlákno skončí, napr. V tomto prípade môžete zabezpečiť, že systém vráti všetky prostriedky automaticky v bode, kde sa vlákno vráti.
Aby ste to dosiahli, mali by ste začať príslušné vlákna s DETACHED postavenie. Keď začínate vlákno, ODPOJIŤ stav možno nastaviť pomocou hodnôt atribútu vlákna alebo pomocou pthread_detach funkcia:
intpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
intpthread_detach(pthread_t vlákno);
Tu je príklad použitia pthread_join(). Nahraďte hlavnú funkciu v prvom programe nasledujúcim:
intHlavná(neplatné)
{
pthread_t th1, th2;
pthread_create(&th1, NULOVÝ, pracovník, "X");
pthread_create(&th2, NULOVÝ, pracovník, "Y");
spať (5);
printf("opustenie hlavného programu\n");
pthread_join (th1, NULOVÝ);
pthread_join (th2, NULOVÝ);
vrátiť0;
}
Keď skompilujete a spustíte program, váš výstup bude:
Ahoj z vlákna Y
Ahoj z vlákna X
Ahoj z vlákna Y
...
Ahoj z vlákna Y
opustenie hlavného programu
Ahoj z vlákna X
...
Ahoj z vlákna X
Vlákno X hotové!
Ahoj z vlákna Y
Vlákno Y hotovo!
Ukončenie vlákna
Vlákno môžete zrušiť volaním pthread_cancel a odovzdaním zodpovedajúceho vlákna pthread_t id:
intpthread_cancel(pthread_t vlákno);
Môžete to vidieť v akcii v nasledujúcom kóde. Opäť len ten Hlavná funkcia je iná:
intHlavná(neplatné)
{
pthread_t th1, th2;
pthread_create(&th1, NULOVÝ, pracovník, "X");
pthread_create(&th2, NULOVÝ, pracovník, "Y");
spať (1);
printf("> Ruším vlákno Y!!\n");
pthread_cancel (th2);
spať (100000);
printf("> Ruším vlákno X!\n");
pthread_cancel (th1);
printf("opustenie hlavného programu\n");
vrátiť0;
}
Prečo sa vytvárajú vlákna?
Operačné systémy sa vždy pokúšajú spustiť vlákna na jednom alebo viacerých procesoroch, a to buď z vlastného zoznamu alebo zo zoznamu vlákien vytvoreného používateľom. Niektoré vlákna nemôžu bežať, pretože čakajú na vstupný/výstupný signál z hardvéru. Môžu tiež čakať dobrovoľne, čakať na odpoveď z iného vlákna alebo ich blokuje iné vlákno.
Prostriedky, ktoré prideľujete vláknam, ktoré vytvoríte, môžete upraviť pomocou pthread. Môže to byť vlastná plánovacia politika, alebo si v prípade potreby môžete vybrať plánovacie algoritmy ako FIFO alebo Round-robin.