PredchádzajúciHoreDomovNasledujúci

POSIX threads, pthread

Knižnica pthread bežne dostupná na unixových systémoch umožňuje spúšťať a synchronizovať programový kód vo vláknach.

Vlákno je v tejto knižnici reprezentované typom pthread_t, každá premenná tohto typu môže reprezentovať jedno vlákno. Na vytvorenie vlákna a spustenie používateľom definovanej funkcie slúži funkcia pthread_create.

Funkcia spúšťaná vo vlákne musí mať nasledovný typ:

void* thread_main(void*);

t.j. musí mať jediný parameter - netypový ukazovateľ a návratová hodnota je opäť netypový ukazovateľ. Vďaka tomu môžme vláknu pri spustení dať k dispozícii ľubovoľné dáta na spracovanie a rovnako môže vlákno vyprodukovať vlastné dáta a vrátiť ukazovateľ na ich umiestnenie v pamäti.

[Dôležité] Dôležité

Tak ako vždy pri práci s ukazovateľmi, musíme dbať na to aby ukazovovateľ ostal platný kým ho používa vlákno alebo jeho volajúci, t.j. ak bol blok pamäti alokovaný dynamicky aby nebol predčasne uvoľnený alebo ak sú dáta umiestnené na zásobníku, aby proces neopustil blok programu, kde boli dáta na zásobník uložené.

Na druhej strane musíme pamätať na správne uvoľnenie dynamicky pridelenej pamäti. Ak pamäť pre vstupné dáta vlákna alokovala dynamicky funkcia, ktorá vlákno spúšťa, je potrebné jednoznačne určiť, kto bude zodpovedný za jej uvoľnenie. Podobne, ak vlákno dynamicky alokovalo pamäť pre výstupné údaje, je potrebné aby bola táto pamäť po dokončení vykonávania vlákna uvoľnená.

V knižnici pthread môže byť vlákno spustené v dvoch rôznych režimoch:

[Dôležité] Dôležité

Zjednodušene je možné povedať, že pre každé vlákno spustené pomocou funkcie pthread_create je potrebné zavolať buď funkciu pthread_join alebo funkciu pthread_detach ale nikdy nie obe.

Cvičenie Vytvorte zdrojový súbor pthread_fib.c s nasledovným obsahom:

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

unsigned dumb_fib(unsigned n) 2
{
	if(n <= 2) return 1;
	else return dumb_fib(n-1)+dumb_fib(n-2);
}

struct fib_data 3
{
	unsigned argument;
	unsigned result;
};

void* thread_main(void* pdata) 4
{
	struct fib_data* thread_data = (struct fib_data*)pdata; 5

	thread_data->result = dumb_fib(thread_data->argument); 6

	return NULL; 7
}

int main(void)
{
	struct fib_data thread_data = {45, 0}; 8

	pthread_t thread; 9

	pthread_create(&thread, NULL, &thread_main, &thread_data); 10

	pthread_join(thread, NULL); 11

	printf("fib(%u) = %u\n", thread_data.argument, thread_data.result); 12

	return 0;
}

1

Ak chceme používať knižnicu pthreads, musíme includnuť tento hlavičkový súbor.

2

Veľmi neefektívny spôsob výpočtu Fibonacciho čísel. Používame ho ako príklad jednoduchého algoritmu s veľkou dobou výpočtu.

3

Štruktúra, ktorú používame na výmenu vstupných a výstupných dát pri výpočte n-tého fibonacciho čísla, medzi hlavným programom a vláknom.

4

Hlavná funkcia vlákna.

5

Netypový ukazovateľ pdata, (ktorý sme dostali od funkcie pthread_create) potrebujeme pretypovať na správny typ.

6

Do premennej result uložíme výsledok výpočtu na argumente argument.

7

Toto vlákno nepotrebuje vrátiť žiadny iný platný ukazovateľ. Celá výmena dát prebieha pomocou štruktúry, na ktorú ukazuje parameter pdata.

8

Vytvoríme a zinicializujeme inštanciu štruktúry fib_data. V premennej argument je 45, výsledok je zatiaľ 0. Táto inštancia je uložená na zásobníku, v kontexte funkcie main, takže potrebujeme zabezpečiť aby proces neopustil túto funkciu skôr ako sa dokončí vykonávanie vlákna, ktoré na túto inštanciu odkazuje pomocou ukazovateľa. Dosiahneme to tak, že na vlákno počkáme pomocou funkcie pthread_join.

9

Táto premenná bude reprezentovať bežiace vlákno.

10

Vytvoríme nové vlákno (identifikované premennou thread), bez dodatočných atribútov, a spustíme v ňom funkciu thread_main, ktorej ako argument chceme odovzdať ukazovateľ na inštanciu thread_data.

11

Keďže vlákno bolo spustené ako joinable, musíme na jeho dokončenie počkať pomocou funkcie pthread_join. V tomto prípade nepotrebujeme získať návratovú hodnotu vlákna.

12

Vypíšeme výsledok výpočtu.

Cvičenie Skopírujte a upravte súbor Makefile z predchádzajúceho cvičenia:

OUTPUTS = pthread_fib

all: $(OUTPUTS)

clean:
        rm -f $(OUTPUTS)
        rm -f *.o

.PHONY: all clean

%: %.c
        $(CC) -lpthread 1 -o $@ $<

1

Ak chceme skompilovať program používajúci knižnicu pthreads, musíme ju prilinkovať pomocou prepínača -lpthread.

Cvičenie Skompilujte a spustite program pthread_fib:

$> make pthread_fib
$> ./pthread_fib

PredchádzajúciHoreDomovNasledujúci