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.
1

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 >


2

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(


3

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;


4

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;


5

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.


6

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.


7

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,


8

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...


9

...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


10

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).


11

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

zdjęcie

Dodaj komentarz

  1. Zaloguj się:
  1. 03.05.2010

Komentarze

Strona wykorzystuje pliki cookies w celu prawidłowego jej działania oraz korzystania z narzędzi analitycznych, reklamowych i społecznościowych. Szczegóły znajdują się w polityce prywatnościRozumiem i akceptuję
Dodaj opinię o stronie
Dodaj opinię o stronie
  1. anuluj