Jak dodać wątki do aplikacji (pthreads)?
W niektórych przypadkach gdy nasze programy przetwarzają duże ilości danych sekwencyjnie warto jest zastosować dodatkowe zabiegi zwiększające szybkość działania algorytmu przetwarzania. W pewnych miejscach gdzie funkcje mogą być duplikowane warto zastosować przetwarzanie równoległe. Jednym z mechanizmów przetwarzania równoległego są wątki - POSIX Threads/pthreads. Jest to o wiele korzystniejszy sposób zwielokrotnienia równoległego wykonywania funkcji od wzbudzania w systemie nowego procesu (fork) ponieważ wykorzystuje znacznie mniej zasobów systemowych do pracy - program ładowany jest raz do pamięci i wykonywany równolegle w tylko konkretnych obszarach. Jak więc zastosować wątki? To proste...
- • kompilator GCC z wbudowanymi bibliotekami pthread.

Na samym początku programu dodajemy deklaracje potrzebnych nagłówków - załączamy je tagiem #include. Nas interesuje głównie moduł wątków, zatem dodajemy nagłówek "pthread.h".
#include < pthread.h >

Następnie deklarujemy wskaźnik do funkcji, którą zechcemy zwielokrotnić poprzez wykonanie wątkami. Nazwijmy ją "FunkcjaC".
FunkcjaC nie przyjmuej parametrów i zwraca VOID, zatem deklaracja będzie wyglądać następująco:
void *funkcjaC(

Do funkcji, która będzie wywoływać wątki (np. blok main()) dodajemy zmienne typu INT, w których przekażemy wskaźniki do wątków lub ewentualne kody błędu:
int w1, w2;

W tym miejscu musimy zadeklarować zmienne wątków, które będziemy używać później - cały czas znajdujemy się w bloku funkcji, która utworzy wątki i je zainicjuje. Typ zmiennej to pthread_t.
pthread_t watek1, watek2;

Stworzymy teraz warunek (IF), który sprawdzi, czy wątek został utworzony, jednocześnie inicjując wątek. Wykorzystujemy zmienne w1 i w2, watek1, watek2 oraz funkcje pthread_create.
if (w1=pthread_create( &watek1, , &funkcjaC, ))
{
printf("Nie udalo sie utworzyc watku: %d
", w1
}
W ten sposób utworzymy pierwszy wątek, bądź uzyskamy kod błędu w przypadku niepowodzenia tej operacji. Warto jest zauważyć, że wykorzystujemy mechanizm przekazania adresu do funkcji i zmiennej wątku, a nie same zmienne oraz nazwę funkcji.

Tworzymy drugi wątek analogicznie do pierwszego:
if (w2=pthread_create( &watek2, , &functionC, ))
{
printf("Nie udalo sie utworzyc watku: %d
", w2
}
Utworzyliśmy drugi wątek - teraz funkcja "funkcjaC" będzie wykonywana równolegle.

W większości przypadków warto jest zsynchronizować wątki w głównej mierze po to, aby w przypadku gdy jeden wątek się zakończy a drugi jeszcze ciągle jest w toku program nie przeszedł do dalszego wykonywania instrukcji. W tym celu wykorzystujemy funkcję pthread_join().
Funkcja pthread_join przyjmuje jako 1 parametr nazwę zmiennej (nie jej wskaźnik), zatem synchronizacja wątków będzie wyglądała następująco:
pthread_join( watek1,
pthread_join( watek2,

Po wykonaniu kroku 7 wątki ulegną synchronizacji (w określonej kolejności - najpierw wątek1, następnie wątek2). Po wykonaniu tych instrukcji program przejdzie do dalszego wykonywania programu. W celach testowych warto jest zastosować tutaj wyjście z programu w formie funkcji systemowej exit() zwracając 0 jako kod błędu - program wykonany prawidłowo.
Zapisujemy plik, sprawdzamy czy nie popełniliśmy jakichś literówek, dopisujemy wnętrze funkcji "funkcjaC" i możemy przystąpić do...

...kompilacji. My w tym celu wykorzystamy kompilator GNU Compiler Collection - GCC. Aby uniknąć błędów związanych z brakiem odpowiednich bibliotek należy koniecznie do polecenia dodać flagę -lpthread. Zakładając że nasz program nazwiemy "main.c".
gcc main.c -o main -lpthread

Możemy teraz przetestować program wykonując go. Jeśli nie będziemy mieli praw do wykonania programu używamy jako superużytkownik polecenia chmod +x na programie. Gdy posiadamy prawa do programu wpisujemy w shellu (np. bash):
./main
Program powinien się wykonać lub wskazać błąd - np. jeśli brak jest zasobów systemowych do wykonania wątku.
Wykonując program wielowątkowy warto jest przemyśleć możliwość wykorzystania mechanizmów zastrzegania dostępu do zasobów systemowych poprzez tzw. mutex (mutual exclusion - wzajemne wykluczenie).
Uwagi i spostrzeżenia
- •Koniecznie podczas kompilacji dodaj flagę -lpthread. Proces kompilacji może być dostępny przy pewnych konfiguracjach tylko z poziomu superużytkownika.
Galeria

Dodaj komentarz