Skočiť na obsah Skočiť na menu

Inet.sk - internetový denník

internetový denník

Vlákna a Linux

V dnešnej časti si povieme o vláknach v operačnom systéme Linux. Naučíme sa vytvárať vlákna a narábať s nimi, joinovať i detachovať vlákna. Taktiež si povieme niečo o chovaní vláken a nebudú chybať ani príklady.


V dnešnej časti si povieme o používaní vláken pod operačným systémom Linux. Uvedieme si aj konkrétne príklady. Operačný systém Linux plánuje vlákna, pričom zohľadňuje viaceré kritéria (Nice hodnota procesu, priorita...), avšak skúmanie plánovacieho procesu Linuxu je nad záber tohoto článku.

V prípade vláken v Linuxe je dôležité si povedať niečo o stavoch. Vlákno sa podobne ako proces, môže nachádzať v stavoch ako running, ready, asleep (blocked) a v stave podobnom stavu zombie. Vlákna sú joinable a detached. Čo tieto dva stavy znamenajú? Vlákno má pridelené určité prostriedky (vlastný zásobník, pamäť (heap)...) a tieto prostriedky treba po ukončení vlákna (návratu z hlavnej rutiny vlákna) uvolniť. Otázka je -  "KEDY?". V prípade, že je vlákno v detached stave, tak sa jeho prostriedky uvoľnia hneď po jeho ukončení (prípadne zrušení). Z takto ukončeného vlákna sa nedá získať návratová hodnota.

Na druhú stranu existuje stav joinable. V tomto stave vlákno po ukončení ostane a čaká na tzv. joinutie (pripojenie). Iné vlákno pomocou špeciálnej funkcie (o ktorej si povieme neskôr) pripojí vlákno a získa jeho návratovú hodnotu. Prostriedky vlákna sú uvoľnené a vlákno sa môže konečne odobrať na odpočinok. Ak vás napadlo, čo sa stane ak vlákno, ktoré pripája iné vlákna "umrie", prípadne sa dostane napr. do nekonečného cyklu, odpoveď je jednoduchá. Vlákna čakajú až do ukončenia procesu, v ktorého adresovom priestore existujú. Teda sa netreba strachovať, že by vám nekonečne dlho čakajúce vlákna plnili pamäť, a žrali prostriedky.

Aby sme trošku prehĺbli predstavu o vláknach, povieme si čo majú thready jedného procesu spoločné - adresový priestor, user ID, group ID, deskriptory, signály, aktuálny adresár (určite som na niečo zabudol, ale tá idea tu je). A povieme si, čo naopak majú vlákna unikátne - identifikátor (ID), zásobník, určité registre procesoru (register vrcholu zásobníku, PC (ukazateľ na najbližsie vykonávanú inštrukciu)), masku signálov, prioritu a chybovú globálnu premennú errno.

Aby som príliš nezdržoval, hneď sa vrhneme na programovanie. Ako prvé si povieme, čo treba urobiť, aby sme mohli vlákna v operačnom systéme Linux používať. Vo svojich zdrojových súboroch treba zainklúdovať súbor pthread.h. Druhá dôležitá vec je pridať pri kompilácii príznak -lpthread.

Ako prvú si predstavíme funkciu, ktorou sa vlákna vytvárajú.

int  pthread_create(pthread_t  *  thread, pthread_attr_t * attr, 
void
* (*start_routine)(void *), void * arg);

Vysvetlíme si jednotlivé argumenty. Podobne ako v operačnom systéme Windows, je i tu vlákno identifikované špeciálnym typom. Obsahom tohoto typu vás nebudem zaťažovať.

Argument thread je pointer na inštanciu premennej typu pthread_t (tento argument musí byť naalokovaný v pamäti, prípadne musí byť globálny, prípadne lokálny). Tento argument sa naplní údajmi o vytvorenom vlákne.

Argument attr špecifikuje atribúty vytváraného vlákna. Jeho presnú štruktúru môžete nájsť v pthreadtypes.h. Čo je pre nás dôležité je tzv. detached state, ktorému sa daju nastaviť hodnoty PTHREAD_CREATE_DETACHED alebo PTHREAD_CREATE_JOINABLE. Ostané parametre sa dajú dohľadať v dokumentácii (napr. velkosť zásobníku, parametre plánvoania, politka plánovania, a iné ). V prípade, že túto premennú zadáte ako NULL, nič sa nedeje, vlákno sa vytvorí s defaultnými hodnotami atribútov.

Argument start_routine je ukazateľ na funkciu, ktorá reprezentuje vykonávaný kód vlákna. Funkcia musí byť v tvare void* NazovFunkcie(void* param)

Argument arg je pointer, ktorý sa hlavnej funkcii vlákna predá ako parameter.

Ukážeme si jednoduchý kód
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

//pocet vypisov
#define MAX_LOOPS 10000

//vlakna
pthread_t thread_a, thread_b, thread_c;

//funkcia ktora je telom vlakna
void* Test(void* id)
{
int i;
//informacne vypisy
printf ("Thread %d startedn", *(int*)id );

//cyklus vypisania
for (i =0; i< MAX_LOOPS; i++)
{
//prvy thread vypise a druhy b atd
printf("%c",(int)'a'-1+(*(int*)id));
}
return NULL;
}

int main( void )
{
int a = 1, b = 2, c = 3;

//vytvorenie vlaken
pthread_create (&thread_a, NULL, Test, &a);
pthread_create (&thread_b, NULL, Test, &b);
pthread_create (&thread_c, NULL, Test, &c);

//pripojenie vlaken
pthread_join( thread_a, NULL);
pthread_join( thread_b, NULL);
pthread_join( thread_c, NULL);

return 0;
}

Po skompilovaní by ste na obrazovke mali vidieť vypísané postupnosti znakov a, b, c. Keď sa pozrieme presnejšie na výpis, uvidíme (nemusí to byť zákonitosť, záleží to od plánovača a iných parametrov) ako sa medzi výpisy ačok dostali bčka prípadne cčka. Keby sme výpis farebne odlíšili, bolo by vidieť, že jednotlivé sekvencie výpisu nie sú konzistetné. Toto je pekný príklad na to, ako dochádza ku kolízii vláken. Pokiaľ by sme chceli, aby výpis ačok bol neprerušený iným výpisom (rovnako aj výpis bčok a cčok), tak by sme museli vlákna synchronizovať (ale o tom neskôr).

Ako ste si všimli, v kóde sme použili funkciu pthread_join.
Syntax tejto funkcie je nasledovná int pthread_join ( pthread_t th, void ** thread_return)

Pokúsim sa Vám vysvetliť význam jednotlivých argumentov. Argument th odkazuje na vlákno ktoré sa má "pripojiť". Do argumentu thread_return sa naplní obsah návratovej hodnoty hlavnej funkcie vlákna. Pozor, aby návratová hodnota nebola lokálneho charakteru, pretože po uvoľnení prostriedkov vlákna dôjde k jej zániku.

Ako ďalšiu funkciu si predstavíme int pthread_exit( void * retval ).
Táto funkcia sa nikdy nevráti zo svojho volania. Je to logické, pretože zaháji ukončenie vlákna. Argument retval ukazuje na hodnotu, ktorá sa má pri prípadnom pripojení vlákna vrátiť ako návratová hodnota vlákna. Znova si treba dať pozor, na to na akú hodnotu odkazujeme v tomto prípade. Ak bude retval odkazovať na lokálnu premennú vlákna, táto sa stane neexistentnou v dobe, kedy sa budú uvoľnovať prostriedky vlákna.

Ako poslednú funkciu si ukážeme funkciu int pthread_detach ( pthread_t th ). Jediný argument th tejto funkcie je štruktúra typu pthread_t. Táto funkcia nastaví vlákno do stavu detached a potom už vlákno netreba pripájať (join) a teda sa o to vlákno ani netreba už starať z pohľadu iných vlákien. Nevýhodou je to, že nezískame žiadnu návratovu hodnotu z vlákna po jeho ukončení. Aby bolo vlákno detached sa dá docieliť i správnym nastavením atribútov pri vytváraní vlákna.

Jednoduchý príklad použitia na záver. V ďalšej časti si povieme o synchronizácii a synchronizačnom primitíve - mutex.


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

//pocet vypisov
#define MAX_LOOPS 10000

//vlakna
pthread_t thread_a, thread_b, thread_c;

//funkcia ktora je telom vlakna
void* Test(void* id)
{
int i;
//informacne vypisy
printf ("Thread %d startedn", *(int*)id );

//cyklus vypisania
for (i =0; i< MAX_LOOPS; i++)
{
//prvy thread vypise a druhy b atd
printf("%c",(int)'a'-1+(*(int*)id));
}
return NULL;
}

int main( void )
{
int a = 1, b = 2, c = 3;

//vytvorenie vlaken
pthread_create (&thread_a, NULL, Test, &a);
//detach
pthread_detach ( thread_a );

pthread_create (&thread_b, NULL, Test, &b);
//detach
pthread_detach ( thread_b );

pthread_create (&thread_c, NULL, Test, &c);

//detach
pthread_detach ( thread_c );

return 0;
}
<= predchádzajúci článok     nasledujúci článok =>

Pôvodná diskusia k článku

1.tie zdrojaky tam mas zle a nesedia k tomu co pisesaspon ten posledny kde pises o ukazke mutexov tak tam ziadne mutexy nepouzivasa vo vsetkych zdrojakoch mas v pthread_create funkciu TestMutex ale v zdrojaku mas nazov funkcie Testtakze sa neda ani skompilovat2.a este dva preklepiky urˇčité zýsobník

27. 06. 2006 stano 195.168.3.xxx

Dobry clanok. Mozno, ze som to prehliadol, ale nenasiel som jednu podstatnu vec. Zakladnou jednotkou v Linux je process a nie vlakno. Jadro nevidi vlakna a ked caka proces, cakaju aj vsetky jeho vlakna - t.j. nevyhoda ale zas ked proces necaka je prepinanie kniznicnych vlakien rychlejsie. Vlakna su implementovane len pomocou kniznic a OS sa nestara o ich administraciu,. Preto sa ako parameter pri kompilovani uvadza tiez -lpthread. Na rozdiel od Windowsu, ktory vlakna rozlisuje a preemtivne ich prepina. Ine je to od jadra 2.6, kde uz su vlakna NPTL vytvarane na urovni OS, aj ked stale na preemtivne prepinaie je potrebne prekopat jadro. Tieto clanku tu naozaj chybaju, preco nepises castejsie?

27. 06. 2006 Michal Cizmar 84.47.104.xxx

Michal Cizmar napísal: Dobry clanok. Mozno, ze som to prehliadol, ale nenasiel som jednu podstatnu vec. Zakladnou jednotkou v Linux je process a nie vlakno. Jadro nevidi vlakna a ked caka proces, cakaju aj vsetky jeho vlakna - t.j. nevyhoda ale zas ked proces necaka je prepinanie kniznicnych vlakien rychlejsie. Vlakna su implementovane len pomocou kniznic a OS sa nestara o ich administraciu,. Preto sa ako parameter pri kompilovani uvadza tiez -lpthread. Na rozdiel od Windowsu, ktory vlakna rozlisuje a preemtivne ich prepina. Ine je to od jadra 2.6, kde uz su vlakna NPTL vytvarane na urovni OS, aj ked stale na preemtivne prepinaie je potrebne prekopat jadro. Tieto clanku tu naozaj chybaju, preco nepises castejsie?mylis sa co sa tyka tych kniznicnich vlakien, predchodca nptl, linuxthreads fungoval takym sposobom ze vsetky vlakna boli normalne procesy, iba data v pameti maly zdielane (ked si si zobrazil procesy cez ps tak si videl vsetky thready)btw. -lpthread treba pouzit vzdy aj pri nptlale ano existuju aj implementacie ktore maju vlakna riesenie cisto v userspace ale defaultne v distribuciach bolo linuxthreads (v niektorych este stale je)a co sa tyka scheduleru a nptl vlakien tak si myslim ze sa scheduluju v kernely ako normalne procesy

27. 06. 2006 Anonym 86.110.225.xxx

Michal Cizmar napísal: Dobry clanok. Mozno, ze som to prehliadol, ale nenasiel som jednu podstatnu vec. Zakladnou jednotkou v Linux je process a nie vlakno. Jadro nevidi vlakna a ked caka proces, cakaju aj vsetky jeho vlakna - t.j. nevyhoda ale zas ked proces necaka je prepinanie kniznicnych vlakien rychlejsie. Vlakna su implementovane len pomocou kniznic a OS sa nestara o ich administraciu,. Preto sa ako parameter pri kompilovani uvadza tiez -lpthread. Na rozdiel od Windowsu, ktory vlakna rozlisuje a preemtivne ich prepina. Ine je to od jadra 2.6, kde uz su vlakna NPTL vytvarane na urovni OS, aj ked stale na preemtivne prepinaie je potrebne prekopat jadro. Tieto clanku tu naozaj chybaju, preco nepises castejsie?@prvy post - chyby opravim. diq, moze sa stat, v tomto teple sa sebe ani nedivim. na druhu stranu je to test inteligencie pre citatela :Pzdar.pojdem od konca. nepisem preto, lebo som leniva osoba a posledne som mal skutocne vela okolo usi. Aktualne sa prave hotujem si prestudovat podrobnejsie kernel internals ako linuxu tak windows.Osobne nevidim do kernelu linuxu podorbne a ohladne planovanych entit som bol pravdepodobne misquided od cloveka co mi to tak nejak zle nastinil. Bolo mi povedane ze od kern 2.6 je to podobne ako windows. Asi som tomu len zle rozumel - by bad.

28. 06. 2006 Anonym 195.113.26.xxx

prispevok nad tymto prispevkom je od autora clnaku

28. 06. 2006 vegetta [autor] 195.113.26.xxx

prispevok do diskusie ma inspiroval napisat trosku detialnejsi clanok o linux kerneli - co ale vyzaduje trosku detailnejsie si to cele nastudovat. cize ak su medzi citatelmi nejaky zaujemci o toto, teste sa :) a dufajte ze cez leto bude vela prsat - aby som sa vela nudil

28. 06. 2006 vegetta [autor] 195.113.26.xxx

Je Vaša doména voľná?

Platená reklama

Textová reklama

Ako začať podnikať na internete? Nechajte si poradiť. Aký má byť obsah kvalitne www stránky? Tvorba www stránok, Tvorba webu, Redakčný systém - CMS, Prieskumy o nakupovaní na internete, Pôžičky
Kompletné informácie o Kika Banská Bystrica | Čo takto navštíviť Viedeň? | Zaujímavé informácie priamo od zdroja

Newsletter


Copyright © 2002 - 2012 Inet.sk, s. r. o.Všetky práva vyhradenéNeprešlo jazykovou úpravouISSN 1336-1899

Využívame kvalitný webhosting za rozumnú cenu od Webhosting Inet.sk


Bilancia skrývky Fotokniha Fotografie Osobnosti.sk