POSIX Threads - Wojciech Muła — website0x80.pl/articles/pthreads.pdf · Niniejszy podręcznik ma...

105
POSIX Threads Wojciech Mula marzec 2010 z późniejszymi poprawkami (plik utworzony 21 marca 2011) Najbardziej aktualna wersja online jest utrzymywana w serwisie Wikibooks. Wersja PDF jest dostępna adresem 0x80.pl. Sklad wykonano programem L A T E X2 ε

Transcript of POSIX Threads - Wojciech Muła — website0x80.pl/articles/pthreads.pdf · Niniejszy podręcznik ma...

POSIX ThreadsWojciech Muła

marzec 2010 z późniejszymi poprawkami(plik utworzony 21 marca 2011)

Najbardziej aktualna wersja online jest utrzymywana w serwisie Wikibooks.Wersja PDF jest dostępna adresem 0x80.pl.

Skład wykonano programem LATEX 2ε

2

Rozdział 1

Wiadomości wstępne

3

1.1. SPIS TREŚCI

Niniejszy podręcznik ma na celu zaznajomienie Czytelnika z biblioteką programistyczną POSIXThreads (w skrócie pthreads). Biblioteka udostępnia jednolite API dla język C do tworzenia i zarzą-dzania wątkami , jest dostępna w systemach m.in. Linux , FreeBSD , Windows .

1.1 Spis treści

• Wstęp

– Podstawowe informacje o bibliotece

– Opcje standardu

– C++

– O podręczniku

• Podstawowe operacje

– Tworzenie wątku

– Identyfikator wątku

– Kończenie wątku

– Oczekiwanie na zakończenie wątku

– Zakończenie procesu, a kończenie wątków

– Rodzaje wątków

– Przekazywanie argumentów i zwracanie wyników

• Atrybuty wątku

– Inicjalizacja

– Rodzaj wątku

– Rozmiar i adres stosu

– Obszar zabezpieczający stosu (guard)

– Szeregowanie wątków

– Zakres konkurowania wątków

• Specjalne działania

– Stos funkcji finalizujących (cleanup)

– Lokalne dane wątku

– Funkcje wywoływane jednokrotnie

– UNIX-owe sygnały

– Przerywanie wątków

– Pthreads i forkowanie

– Stopień współbieżności

– Czas procesora zużyty przez wątek

• Synchronizacja między wątkami

– Mutexy

– Zmienne warunkowe (condition variable)

– Blokady zapis/odczyt (rwlock)

– Bariery

4

1.1. SPIS TREŚCI

– Wirujące blokady (spinlock)

– Synchronizacja między wątkami różnych procesów

• Niestandardowe rozszerzenia

– Linuxa

– HP-UX

– Cygwina

• Przykładowe programy

• Indeks

5

1.2. PODSTAWOWE INFORMACJE O BIBLIOTECE

1.2 Podstawowe informacje o bibliotece

Specyfikacja POSIX jest dostępna nieodpłatnie na stronie organizacji Open Group (http://www.opengroup.org/). Dla wygody Czytelnika linkujemy w tym podręczniku do konkretnych podstron opi-sujących funkcje.

Opis części implementacji dla systemu Linux znajduje się na stronie The Linux man-pages project(http://www.kernel.org/doc/man-pages/).

Niektóre strony podręczników zawierają przykładowe programy.

1.2.1 Pliki nagłówkowe

Podstawowy plik nagłówkowy biblioteki POSIX Threads nazywa się pthread.h i jego włączeniedo programu jest konieczne. Dokładny wykaz funkcji znajdujący się w tym pliku, wraz z adnotacjamiopcji, znajduje się na stronie http://www.opengroup.org/onlinepubs/009695399/basedefs/pthread.h.html.

Oprócz niego:

• sys/types.h — typy danych (domyślnie włączane przez pthreads.h)

• limits.h — stałe określające ograniczenia biblioteki

1.2.2 Konwencje nazewnicze

Nazwy funkcji i typów zaczynają się zawsze od pthread , stałe są pisane wielkimi literami i podob-nie rozpoczynają od PTHREAD . Nazewnictwo poza tym jest bardzo konsekwentne, podobnie kolejnośćargumentów itd.

1.2.3 Typy danych

Typy definiowane przez bibliotekę powinny być traktowane jako abstrakcyjne — jedynym sposobemich inicjalizacji, zmiany wartości, itd. jest użycie dedykowanych funkcji.

UWAGA

Nie można po zainicjowaniu obiektu utworzyć jego kopii np. wykonując funkcjęmemcpy, ponieważ biblioteka może równolegle utrzymywać jakieś dodatkoweinformacje dotyczące danego obiektu.

Nazwy funkcji tworzących obiekty są zgodne ze schematem pthread XXX init, natomiast niszcząceobiekt pthread XXX destroy.

1.2.4 Atrybuty

Wszelkie dodatkowe parametry obiektów tworzonych w bibliotece są opisywane atrybutami, tj. inny-mi obiektami, które przechowują określone parametry. Obiekty atrybutów mogą być używane wielokrotniedo tworzenia różnych obiektów.

1.2.5 Zgłaszanie błędów

Większość funkcji z pthreads zwraca wartości typu int, która określa status operacji. Jeśli jest równyzero, funkcja wykonała się poprawnie, w przeciwnym razie zwracana jest standardowa wartość błędu (wrodzaju EINVAL, ENOMEM, EBUSY).

6

1.3. OPCJE STANDARDU

Można więc używać funkcji strerror, ewentualnie przypisywać wynik do zmiennej errno i korzystaćz funkcji perror. Standard POSIX określa, że errno w środowisku wielowątkowym jest lokalne względemwątku.

Na przykład:

\begin{enumerate}

\item include <string.h>\item include <errno.h>\end{enumerate}int main() {int status;

status = pthread_XXX(...);if (status)printf("Błąd przy wywoływaniu pthread_XXX: %s", strerror(status));

errno = pthread_XXX(...);if (errno)perror("pthread_XXX");

return 0;}

1.2.6 Dane użytkownika

Wszystkie dane użytkownika są przekazywane przez wskaźniki typu void*. O interpretacji wskaźnikówi danych na które wskazują decyduje wyłącznie programista, biblioteka pthreads nie określa ani nieogranicza tego w żaden sposób.

1.2.7 Kompilacja

Ponieważ pthreads jest zewnętrzną biblioteką należy linkerowi podać ścieżkę do pliku bibliotecznego.Np. przy kompilacji gcc należy dodać opcję -lpthread.

1.3 Opcje standardu

Implementacja biblioteki pthreads nie musi dostarczać wszystkich funkcji opisanych w standardzie,dopuszcza on szereg opcjonalnych rozszerzeń. W tym podręczniku posługujemy się skrótami używanymina stronach Open Group:

• rozszerzenia (XSI)

– zmiana/odczyt rozmiaru zabezpieczającego stosu

– wybór typu mutexu

– zmiana/odczyt stopnia współbieżności

• bariery (BAR)

• wirujące blokady (SPI)

• zmiana priorytetu wątku posiadającego blokadę (TPP — Thread Priority Protection, TPI —Thread Priority Inheritance)

• szeregowanie wątków (TPS — Thread Execution Scheduling)

7

1.4. C++

• synchronizacja między wątkami różnych procesów (TSH — Thread Process-Shared Synchroniza-tion)

• dodatkowy algorytm szeregowania dla zadań aperiodycznych w systemach czasu rzeczywistego(TPS — Thread Sporadic Server)

• Rozmiar i adres stosu (TSS — Thread Stack Size Attribute)

• Rozmiar i adres stosu (TSA — Thread Stack Address Attribute)

• możliwość wyboru zegara odmierzającego czas przy oczekiwaniu na zmienną warunkową; domyślnieużywany jest zegar systemowy (CS — Clock Selection)

• czas procesora zużyty przez wątek (TCT — Thread CPU-Time Clocks)

• możliwość ograniczonego czasowo oczekiwania na uzyskanie blokad (mutexy) oraz blokad do odczy-tu/zapisu (TMO — Timeouts)

1.4 C++

Użycie biblioteki pthreads w programach pisanych w języku C++ jest oczywiście możliwe. Należyjednie w procedurach wykonywanych w wątkach (patrz Tworzenie wątku) obsługiwać wszystkie wyjątki:

void* wątek(void* arg) {try {// ...// treść wątku// ...}catch (wyjątek1) {// obsługa wyjątku 1}catch (wyjątek2) {// obsługa wyjątku 2}catch (...) {// wszystkie pozostałe wyjątki}}

Uwaga! Przerywanie wątków w implementacji NPTL jest realizowane poprzez zgłoszenie wyjąt-ku — jeśli w wątku zostanie użyte catch (...), wówczas program zakończy się komunikatem FATAL:exception not rethrown. Urlich Drepper [http://udrepper.livejournal.com/ wyjaśnia na swoim blogu],jak objeść ten problem.

1.5 O podręczniku

1.5.1 Przykłady

Przykładowe programy mają jedynie na celu zilustrowanie pewnych cech biblioteki. Jednocześniesą to w pełni funkcjonalne programy — każdy może je skopiować do swojego komputera, skompilowaći uruchomić. Mają być ułatwieniem dla własnych eksperymentów lub testów.

1.5.2 Autorzy

• Wojciech Muła

8

Rozdział 2

Podstawy

9

2.1. TWORZENIE WĄTKU

2.1 Tworzenie wątku

W programie korzystającym z biblioteki pthreads, tuż po uruchomieniu działa dokładnie jeden wątek,wykonujący funkcję main.

Aby utworzyć nowe wątki programista podaje funkcję (dokładniej: adres funkcji), która ma zostaćw nim wykonana — pthread create tworzy i od razu uruchamia wątek, oraz zwraca jego identyfikator.Oczywiście jedna funkcja może być wykorzystywana do utworzenia wielu wątków. Funkcja użytkownikaprzyjmuje i zwraca wartość typu void*, interpretacja tych danych jest zależna od programu, pthreadsnie narzuca więc tutaj żadnych ograniczeń. Wątki mogą być tworzone z poziomu dowolnego innego wątku.

Wątek identyfikuje wartość pthread t, która jest argumentem dla większości funkcji bibliotecznych.Liczba wątków, jakie można utworzyć jest ograniczona przez stałą PTHREAD THREADS MAX (z pliku

limits.h) oraz rzecz jasna przez zasoby systemowe.Infobox—W Cygwinie PTHREAD THREADS MAX nie jest zdefiniowane, ponieważ system MS Windows

pozwala utworzyć dowolną liczbę wątków

2.1.1 Typy

• pthread t

– identyfikator wątku

• pthread attr t

– atrybutów wątku

2.1.2 Funkcje

• int pthread create(pthread t *id, const pthread attr t *attr, void* (fun*)(void*),void* arg)

– id — identyfikator wątku;

– attr — wskaźnik na atrybuty wątku, określające szczegóły dotyczące wątku; można podaćNULL, wówczas zostaną użyte domyślne wartości;

– fun — funkcja wykonywana w wątku; przyjmuje argument typu void* i zwraca wartość tegosamego typu;

– arg — przekazywany do funkcji.

2.1.3 Przykład

Poniższy program typu hello world tworzy (w wątku głównym) kilka innych wątków, wykonującychfunkcję watek i czeka na ich zakończenie. Używane są domyślne atrybuty wątku.

⇒ Przejdź do przykładowego programu nr 1.

2.2 Identyfikator wątku

Wewnętrzna struktura typu pthrad t (podobnie jak innych używanych w pthreads) jest określonaprzez implementację. Jedyną operacją, jaką można wykonać na identyfikatorach jest ich porównanie zewzględu na równość funkcją pthread equal.

Funkcja pthread self zwraca identyfikator wywołującego wątku, co czasem jest przydatne.

10

2.3. KOŃCZENIE WĄTKU

2.2.1 Funkcje

• int pthread equal(pthread t id1, pthread t id2)

– stwierdzenie, czy identyfikatory wątków są równe

• pthread t pthread self()

– zwraca identyfikator wywołującego wątku

2.3 Kończenie wątku

Wątek jest kończony w chwili, gdy funkcja użytkownika przekazana w pthread create zwraca stero-wanie do wywołującego ją kodu, a więc w miejscu wystąpienia instrukcji return.

Ponadto istnieje funkcja pthread exit, która powoduje zakończenie wątku — może zostać użytaw funkcjach wywoływanych z funkcji wątku.

2.3.1 Przykład

W przykładowym programie zakończenie wątku powoduje wywołanie pthread exit na 6. poziomiezagnieżdżenia funkcji koniec watku.

⇒ Przejdź do przykładowego programu nr 3.

Wyjście:

$ ./przykladlicznik = 0, limit = 5licznik = 1, limit = 5licznik = 2, limit = 5licznik = 3, limit = 5licznik = 4, limit = 5licznik = 5, limit = 5

2.4 Oczekiwanie na zakończenie wątku

Oczekiwanie na zakończenie wątku jest dodatkowym sposobem synchronizacji między wątkami i doty-czy wyłącznie wątków typu joinable (zobacz Rodzaje wątków poniżej). Wątek wywołujący pthread joinzostaje wstrzymany do chwili, gdy wskazany wątek zakończy działanie — wówczas wątek oczekujący jestkontynuowany, a pthread join przekazuje wartość wynikową zwróconą przez wątek. Jeśli wątek zostałprzerwany wartością zwracaną jest stała PTHREAD CANCELED.

UWAGA

Jeśli wątek ”zapętli się”, oczekujący na jego zakończenie inny wątek nie jestjuż w stanie nic zrobić.

Oczekiwanie na zakończenie wątku można uzyskać zmiennymi warunkowymi (dodatkowo bez ograni-czań na rodzaj wątku), wymaga to jednak dodatkowej pracy ze strony programisty.

2.4.1 Funkcje

• int pthread join(pthrea t id, void **retval)

– id — identyfikator wątku, którego zakończenie jest oczekiwane;

– retval — wskaźnik na wartość wynikową wątku; może być NULL, wówczas wynik jest ignoro-wany

11

2.5. ZAKOŃCZENIE PROCESU, A KOŃCZENIE WĄTKÓW

2.5 Zakończenie procesu, a kończenie wątków

Kiedy kończy się proces, wszystkie wątki utworzone w jego obrębie są również (gwałtownie) kończone.Dlatego koniecznie trzeba użyć albo wbudowanego mechanizmu synchronizacji, albo jakiegoś własnegorozwiązania.

2.6 Rodzaje wątków

W pthreads wątki są dwojakiego rodzaju:

• joinable (domyślny rodzaj)

• detached

Rodzaj jest ustalany w atrybutach wątku. Można jednak po utworzeniu wątku zmienić typ z joinable nadetached funkcją pthread detach; odwrotne działanie nie jest możliwe.

Wątek typu joinable to taki, z którego można odczytać wartość wynikową zwróconą przez funkcję. Gdywątek tego typu kończy się, jego zasoby nie są zwalniane do chwili wywołania funkcji pthread join(patrz Oczekiwanie na zakończenie wątku).

Warto więc zwrócić uwagę, że utworzenie wątku typu joinable i nie wywołanie wspomnianej funk-cji skutkować będzie wyciekiem pamięci (następstwem którego tworzenie nowych wątków może stać sięniemożliwe).

Wątek typu detached z chwilą zakończenia działania od razu zwalnia wszystkie zasoby; funkcjapthread join nie akceptuje identyfikatorów do wątków tego typu.

2.6.1 Funkcje

• int pthread detach(pthread t id)

– zmiana rodzaju wątku

2.7 Przekazywanie argumentów i zwracanie wyników

2.7.1 Przekazywanie argumentów

Funkcja wykonywana w wątku przejmuje argument typu void* podawany w funkcjipthread create — wskaźnik ten może więc wskazywać dowolną strukturę, może być także pusty.

UWAGA

Ponieważ przekazywane są wskaźniki, dla każdego trzeba wątku przypisaćosobny obiekt argumentów

Można również rzutować bezpośrednio typy, których rozmiar nie przekracza rozmiaru wskaźnik, tzn.gdy sizeof(typ) <= sizeof(void*); mogą to być typy int, short, char, być może też inne — zależnieod platformy sprzętowej i kompilatora.

2.7.2 Zwracanie wyniku

Funkcja użytkownika zwraca wskaźnik na void*. Jeśli potrzeba zwrócić jakieś dane, należy je zaalo-kować na stercie funkcją malloc lub podobną.

UWAGA

Zwracanie wskaźników do obiektów lokalnych (utworzonych na stosie) jest błę-dem — nie tylko w programach wielowątkowych!

12

2.7. PRZEKAZYWANIE ARGUMENTÓW I ZWRACANIE WYNIKÓW

Można również rzutować na void*, tak samo jak w przypadku przekazywania argumentów.

2.7.3 Przykład

⇒ Przejdź do przykładowego programu nr 2.

Wyjście:

$ ./przykladWitaj Wikibooks w dniu 2010-03-14Wątek 2 wywołany z argumentem liczbowym 27wątek 2 zwrócił napis: ’xxxxxxxxxxxxxxxxxxxxxxxxxxx’

13

2.8. ATRYBUTY WĄTKÓW

2.8 Atrybuty wątków

Atrybuty wątku pozwalają ustawić szereg parametrów wątków podczas ich tworzenia. Pojedynczyobiekt atrybutów może być wykorzystany wielokrotnie do tworzenia różnych wątków.

Wszystkie atrybuty wątku opisuje typ pthread attr t. Nazwy funkcji operujących na tym ty-pie zaczynają się od pthread attr. Funkcje ustawiające poszczególne atrybuty zaczynają się odpthread attr set i istnieją dla nich odpowiedniki odczytujące pthread attr get.

2.9 Inicjalizacja

Przed użyciem atrybutu zmienna musi zostać zainicjowana funkcją pthread attr init, zwolnieniezasobów z nim związanych realizuje funkcja pthread attr destroy.

2.9.1 Typy

• pthread attr t

2.9.2 Funkcje

• int pthread attr init(pthread attr t *attr)

• int pthread attr destroy(pthread attr t *attr)

2.9.3 Przykład

pthread_attr_t atrybuty;

pthread_attr_init(&atrybuty);/* ... */pthread_attr_destroy(&atrybuty);

2.10 Rodzaj wątku

Rodzaje wątków zostały dokładniej opisane w innej sekcji. Funkcje pthread attr setdetachstateustawia, zaś pthread attr getdetachstate odczytuje rodzaj wątku, jaki ma zostać ustalony przy jegotworzeniu. Rodzaj jest identyfikowany jedną z wartości:

• PTHREAD CREATE JOINABLE — utworzenie wątku typu joinable (domyślnie);

• PTHREAD CREATE DETACHED — utworzenie wątku typu detached.

2.10.1 Funkcje

• int pthread attr setdetachstate(pthread attr t *attr, int detachstate)

– ustawienie rodzaju

• int pthread attr getdetachstate(const pthread attr t *attr, int *detachstate)

– odczyt

14

2.11. ROZMIAR I ADRES STOSU

2.11 Rozmiar i adres stosu

Domyślny rozmiar stosu wątku zależy od implementacji i może być rzędu kilku-kilkudziesięciu kilo-bajtów lub kilku megabajtów. Należy liczyć się z tym, że rozmiar będzie wewnętrznie zaokrąglony dorozmiaru strony pamięci (PAGE SIZE — 4kB na procesorach x86). Zmiana rozmiaru jest możliwa jeżelibiblioteka pthreads implementuje opcję TSS.

Samodzielne ustalenie rozmiaru stosu może być konieczne, gdy funkcja wątku tworzy duże obiekty nastosie lub przeciwnie — gdy wiadomo, że wątki nie potrzebują zbyt wiele pamięci, a jednocześnie będziepotrzebna dużą ich liczba. Rozmiar stosu nie może być mniejszy od stałej PTHREAD STACK MIN (z plikulimits.h) ani przekraczać możliwości systemu.

Jeśli biblioteka implementuje opcję TSA można również ustalić adres stosu.

UWAGA

Zmiana adresu stosu może być nieprzenośne ze względu na to, że wskaźnikstosu może albo zmniejszać albo zwiększać adres przy odkładaniu elementówna stosie

2.11.1 Funkcja

• int pthread attr setstacksize(pthread attr t *attr, size t stacksize)

– ustalenie nowego rozmiaru stacksize

• int pthread attr getstacksize(const pthread attr t *attr, size t *stacksize)

– odczyt rozmiaru

• int pthread attr setstackaddr(pthread attr t *attr, void *stackaddr)

– ustalenie nowego rozmiaru stosu stackaddr

• int pthread attr getstackaddr(const pthread attr t *attr, void **stackaddr)

– odczyt adresu

• int pthread attr setstack(pthread attr t *attr, void *stackaddr, size t stacksize)

– jednoczesne ustalenie adresu i rozmiaru stosu

• int pthread attr getstack(const pthread attr t *attr, void **stackaddr, size t *stacksize)

– odczyt adresu i rozmiaru

2.11.2 Przykład

W programie uruchamiany jest wątek, który na stosie alokuje względnie dużą tablicę (ok. 200kB),następnie tablica jest czyszczona. Program z linii poleceń odczytuje żądany rozmiar stosu — ustawiającjego wartość na zbyt małą z pewnością doprowadzimy do błędu SIGSEGV.

⇒ Przejdź do przykładowego programu nr 12.

2.12 Obszar zabezpieczający stosu

Opcja XSI . Jeśli rozmiar obszaru zabezpieczającego (guard) jest większy do zera, za stosem wątkurezerwowana jest pamięć (o rozmiarze zaokrąglonym w górę do rozmiaru strony, tj. PAGE SIZE), która niemoże być zapisywana ani odczytywana. Ułatwia to detekcję części powszechnych błędów polegających nawyjściu poza stos, czyli np. jego przepełnienie, są bowiem sygnalizowane przez sygnał SIGSEGV.

Domyślnie obszar ten jest włączony i ma minimalną wielkość.

15

2.13. SZEREGOWANIE WĄTKÓW

2.12.1 Funkcje

• int pthread attr setguardsize(pthread attr t *attr, size t guardsize)

– ustawienie rozmiaru obszaru zabiezpieczającego

• int pthread attr getguardsize(const pthread attr t *attr, size t *guardsize)

– jego odczyt

2.13 Szeregowanie wątków

Wątki, podobnie jak procesy, mogą działać z różnymi priorytetami i być szeregowane przez różnealgorytmy. Jest to opcja standardu TPS.

2.13.1 Dziedzicznie ustawień

Wątek tworzony funkcją pthread create może albo dziedziczyć ustawienia szeregowania z wywołu-jącego wątku, albo uwzględniać wartości z atrybutów. Ten parametr opisują dwie wartości:

• PTHREAD INHERIT SCHED — ustawienia dziedziczone,

• PTHREAD EXPLICIT SCHED — ustawienia odczytywane z atrybutów.

Funkcje

• int pthread attr getinheritsched(const pthread attr t *attr, int *inheritsched)

– ustawienie parametru

• int pthread attr setinheritsched(pthread attr t *attr, int inheritsched)

– odczytanie parametru

2.13.2 Wybór algorytmu szeregowania

Wartość określająca algorytm szeregowania przyjmuje wartości:

• SCHED OTHER (domyślnie),

• SCHED FIFO,

• SCHED RR,

• SCHED SPORADIC (tylko jeśli dostępna jest opcja TSP).

UWAGA

Wybór algorytmu może być ograniczony uprawnieniami użytkownika.

Funkcje

• int pthread attr setschedpolicy(pthread attr t *attr, int policy)

– ustawienie algorytmu

• int pthread attr getschedpolicy(pthread attr t *attr, int *policy)

– odczyt

16

2.13. SZEREGOWANIE WĄTKÓW

2.13.3 Wybór algorytmu szeregowania i ustawienie jego parametrów (m.in.priorytet)

Oprócz algorytmu szeregowania można również określić jego parametry, w szczególności priorytetwątku.

Priorytet wątku jest niezależny od priorytetu procesu.

Parametry algorytmu opisuj struktura sched param (z sched.h), która zawiera co najmniej jednopole określające priorytet:

struct sched_param {int sched_priority; /* priorytet */};

Jeśli biblioteka implementuje opcję TPS (algorym SCHED SPORADIC), struktura zawiera więcej pól.Wartość priorytetu jest ograniczona wartościami zwracanymi przez funkcje

sched get priority min/max, które zależą od wybranego algorytmu szeregowania.

Funkcje

• int pthread setschedparam(pthread t thread, int policy, const struct sched param*param)

– ustawienie algorytmu i jego parametrów

• int pthread getschedparam(pthread t thread, int *policy, struct sched param*param)

– odczyt

Info—odczytane parametry nie uwzględniają chwilowych zmian priorytetów, np. spowodowanych ochronąpriorytetów w sekcjach krytycznych.

2.13.4 Przykład

Program pozwala wybrać algorytm szeregowania, po czym tworzy kilka wątków z co raz większymipriorytetami (z dopuszczalnego zakresu).

⇒ Przejdź do przykładowego programu nr 19.

Przykładowe wyjście w systemie Linux dla dostępnych algorytmów szeregowania.

$ ./przyklad 0SCHED_OTHER: priorytety w zakresie 0 ... 0utworzono wątek #0 o priorytecie 0utworzono wątek #1 o priorytecie 0utworzono wątek #2 o priorytecie 0utworzono wątek #3 o priorytecie 0wątek #0 (priorytet 0): licznik = 30630wątek #1 (priorytet 0): licznik = 30631wątek #2 (priorytet 0): licznik = 30633wątek #3 (priorytet 0): licznik = 30620

$ ./przyklad 1SCHED_RR: priorytety w zakresie 1 ... 99utworzono wątek #0 o priorytecie 1

17

2.14. ZAKRES KONKUROWANIA WĄTKÓW

utworzono wątek #1 o priorytecie 33utworzono wątek #2 o priorytecie 66utworzono wątek #3 o priorytecie 99wątek #0 (priorytet 1): licznik = 146812wątek #1 (priorytet 33): licznik = 150084wątek #2 (priorytet 66): licznik = 151116wątek #3 (priorytet 99): licznik = 150744

$ ./przyklad 2SCHED_FIFO: priorytety w zakresie 1 ... 99utworzono wątek #0 o priorytecie 1utworzono wątek #1 o priorytecie 33utworzono wątek #2 o priorytecie 66utworzono wątek #3 o priorytecie 99wątek #0 (priorytet 1): licznik = 146659wątek #1 (priorytet 33): licznik = 149249wątek #2 (priorytet 66): licznik = 150764wątek #3 (priorytet 99): licznik = 150895

2.14 Zakres konkurowania wątków

Pthreads pozwala opcjonalnie określić, czy szeregowanie wątków będzie wykonywane w obrębie ca-łego systemu (tzn. ze wszystkimi innymi wątkami i procesami), czy tylko w obrębie wątków z jednegoprocesu. Jest to opcja standardu TPS.

Stałe określające zakres konkurowania:

• PTHREAD SCOPE SYSTEM — system,

• PTHREAD SCOPE PROCESS — proces.

Funkcje

• int pthread attr setscope(pthread attr t *attr, int contentionscope)

– ustawienie zakresu

• int pthread attr getscope(const pthread attr t *attr, int *contentionscope)

– odczyt

2.15 Przykład

Poniższy program wyświetla wszystkie informacje nt. atrybutów wątku.

⇒ Przejdź do przykładowego programu nr 4.

Przykładowe wyjście dla domyślnych ustawień atrybutów (w systemie Linux):

$ ./przykladatrybuty wątku* rodzaj: joinable* adres stosu: (nil)* rozmiar stosu: 8388608 (minimalny 16384)* rozmiar obszaru zabezpieczającego: 4096* parametry szeregowania dziedziczone* zakres szeregowania: system

18

Rozdział 3

Zaawansowane działania

19

3.1. STOS FUNKCJI FINALIZUJĄCYCH (CLEANUP)

3.1 Stos funkcji finalizujących (cleanup)

Z każdym wątkiem związany jest stos funkcji finalizujących (cleanup stack) — jest to osobny stosna którym zapisywane są funkcje użytkownika i argumenty dla nich (przez pthread cleanup push), którenastępnie mogą być wywołane wprost przy ściąganiu ze stosu (pthread cleanup pop).

Ponadto stos funkcji jest automatycznie czyszczony — tzn. ściągane i wykonywane są kolejne funk-cje przy asynchronicznym przerwaniu wątku oraz gdy wątek jest kończony wywołaniem pthread exit.Jeśli wątek kończy się wykonaniem instrukcji return, wówczas to programista jest odpowiedzialny za wy-czyszczenie stosu poprzez wywołanie odpowiednią liczbę razy funkcji pthread cleanup pop. Co prawdastandard nakłada na implementację konieczność zagwarantowania, że te dwie funkcje występują w blo-ku kodu (makra preprocesora), jednak wyjście z bloku instrukcją return, break, continue lub gotojest niezdefiniowane. (Np. w Cygwinie otrzymałem błąd SIGSEGV, w Linuxie błąd został po cichuzignorowany).

Funkcja użytkownika zwraca i przyjmuje argument typu void*.Zastosowaniem opisanego mechanizmu jest zwalniania zasobów przydzielonych wątkowi — np. zwol-

nienie blokad, dealokacja pamięci, zamknięcie plików, gniazd. Jest on nieco podobny do znanego z językaC++ automatycznego wołania destruktorów przy opuszczaniu zakresu, w którym zostały utworzone.

3.1.1 Funkcje

• int pthread cleanup push(void (fun*)(void*), void *arg)

– odłożenie na stos adresu funkcji fun, która przyjmuje argument arg

• int pthread cleanup pop(int execute)

– zdjęcie ze stosu funkcji i jeśli execute jest różne od zera, wykonanie jej

3.1.2 Przykład

W przykładowym programie dwa wątki alokują pamięć. Jeden wątek wprost wywołuje funkcjępthread cleanup pop, w drugim funkcja finalizująca jest wywoływana automatycznie po wykonaniupthread exit.

⇒ Przejdź do przykładowego programu nr 5.

Wyjście:

$ ./przykladwątek #0 zaalokował 100 bajtów pod adresem 0x9058098wątek #1 zaalokował 100 bajtów pod adresem 0x9058190wątek #0 zaalokował 200 bajtów pod adresem 0x90581f8wątek #1 zaalokował 200 bajtów pod adresem 0x90582c8zwalnianie pamięci spod adresu 0x90581f8zwalnianie pamięci spod adresu 0x9058098wątek #0 zakończył sięzwalnianie pamięci spod adresu 0x90582c8zwalnianie pamięci spod adresu 0x9058190

3.2 Lokalne dane wątku

W pthreads istnieje możliwość przyporządkowania kluczom, które są jednakowe dla wszystkichwątków, wskaźnika do danych specyficznych dla danego wątku. W istocie jest to powiązanie pary (klucz,wątek) z danymi, przy czym odwołanie do danych wymaga podania jedynie klucza — wywołujący wątekjest domyślnym drugim elementem pary. Ułatwia to m.in. przekazywanie danych do funkcji wywoływanychz poziomu wątków.

20

3.2. LOKALNE DANE WĄTKU

Z kluczem można związać funkcję (destruktor), która jest wywoływana przy zakończeniu wątku je-śli dane wątku są różne od NULL. Gdy istnieje więcej kluczy, kolejność wywoływania destruktorów jestnieokreślona.

Jeśli klucz został utworzony (pthread key create) to dane dla nowotworzonego wątku są automa-tycznie inicjowane na wartość NULL. Błędem jest próba sięgnięcia lub zapisania danych dla nieistniejącegoklucza.

Liczba dostępnych kluczy jest ograniczona stałą PTHREAD KEY MAX.

3.2.1 Typ

• pthread key t

3.2.2 Funkcje

• int pthread key create(pthread key t *key, void (destructor*)(void*))

– utworzenie nowego klucza, przypisanie destruktora

• int pthread key delete(pthread key t key)

– usunięcie klucza

• int pthread setspecific(pthread key t key, const void *data)

– przypisanie do klucza danych wątku

• void* pthread getspecific(pthread key t key)

– pobranie danych związanych z kluczem.

3.2.3 Przykład

W programie tworzony jest jeden klucz, z którym wątki kojarzą napis — przedrostek, którym funkcjawyswietl poprzedza wyświetlane komunikaty.

⇒ Przejdź do przykładowego programu nr 10.

Przykładowe wyjście:

adres napisu: 0x9bd6008 (’***’)adres napisu: 0x9bd60a8 (’!!!’)!!!: Witaj w równoległym świecie!adres napisu: 0x9bd6148 (’###’)###: Witaj w równoległym świecie!***: Witaj w równoległym świecie!!!!: Wątek wykonuje pracę***: Wątek wykonuje pracę###: Wątek wykonuje pracę!!!: Wątek zakończonywywołano destruktor, adres pamięci do zwolnienia: 0x9bd60a8 (’!!!’)***: Wątek zakończonywywołano destruktor, adres pamięci do zwolnienia: 0x9bd6008 (’***’)###: Wątek zakończonywywołano destruktor, adres pamięci do zwolnienia: 0x9bd6148 (’###’)

21

3.3. FUNKCJE WYWOŁYWANE JEDNOKROTNIE

3.3 Funkcje wywoływane jednokrotnie

Czasem istnieje potrzeba jednokrotnego wykonania jakiejś funkcji, np. w celu inicjalizacji jakiś global-nych ustawień, biblioteki, otwarcia plików, gniazd itp. Pthreads udostępnia funkcję pthread once, któraniezależnie od liczby wywołań, uruchamia dokładnie raz funkcję użytkownika.

Jednokrotne uruchomienie gwarantuje obiekt typu pthread once t; zmienną tego typu należy sta-tycznie zainicjować wartością PTHREAD ONCE INIT.

3.3.1 Typy

• pthread once t

3.3.2 Funkcje

• int pthread once(pthread once t *once, void (fun*)(void))

3.3.3 Przykład

⇒ Przejdź do przykładowego programu nr 6.

Wynik:

$ ./przykladRozpoczynanie programuUruchomiono wątek nr 0Uruchomiono wątek nr 2Uruchomiono wątek nr 1Uruchomiono wątek nr 3Uruchomiono wątek nr 4Uruchomiono wątek nr 5Uruchomiono wątek nr 6Uruchomiono wątek nr 7Uruchomiono wątek nr 8Uruchomiono wątek nr 9

3.4 UNIX-owe sygnały

Gdy sygnał zostanie dostarczony do procesu nie jest określone w kontekście którego wątku wykonasię procedura obsługi sygnału.

3.4.1 Blokowanie sygnałów

Pthreads umożliwia zablokowanie określonych sygnałów na poziomie wątków, służy temu funkcjapthread sigmask (analogiczna do sigprocmask), która modyfikuje zbiór zablokowanych sygnałów wy-wołującego ją wątku. Nie można zablokować SIGFPE, SIGILL, SIGSEGV ani SIGBUS

Funkcje

• int pthread sigmask(int how, const sigset t *set, sigset t *oset)

– how określa jak zbiór set wpływa na bieżący zbiór

∗ SIG BLOCK — włączenie wskazanych sygnałów do zbioru∗ SIG UNBLOCK — odblokowanie wskazanych sygnałów∗ SIG SETMASK — zastąpienie bieżącego zbioru nowym

22

3.5. PRZERYWANIE WĄTKÓW

– gdy oset nie jest pusty, poprzednia maska sygnałów zapisywana jest pod wskazywanym adre-sem

3.4.2 Wysyłanie sygnałów do wątków

Wysyłanie sygnału do określona wątku umożliwia funkcja pthread kill. Jeśli numer sygnału jestrówny zero, wówczas nie jest wysyłany sygnał, ale są testowane jedynie ewentualne błędy — a więc czywskazany identyfikator wątku jest poprawny.

UWAGA

Sygnały, które dotyczą procesów, lecz zostaną wysłane do wątku nie zmieniająswojego znaczenia. Np. wysłanie SIGSTOP zatrzyma proces, a nie wątek.

Funkcje

• int pthread kill(pthread t id, int signum)

– id — wątek

– signum — numer sygnału

3.4.3 Przykład

W przykładowym programie wątek główny czeka na sygnał SIGUSR1, który po pewnym czasie wysyłautworzony wcześniej wątek.

⇒ Przejdź do przykładowego programu nr 13.

Wyjście:

$ ./przykladwątek główny oczekuje na sygnałwątek się rozpocząłwątek wysyła sygnał SIGUSR1 do głównego wątkuwątek główny otrzymał sygnał SIGUSR1

3.5 Przerywanie wątków

Wskazany wątek może zostać przerwany, jeśli tylko nie zostało to wprost zabronione. Sygnał przerwa-nia wysyła funkcja pthread cancel.

Sposób przerwania wątku jest dwojaki:

1. Asynchroniczny — przerwanie następuje natychmiast, w dowolnym momencie.

2. Opóźniony (deferred) — przerwanie następuje dopiero po osiągnięciu tzw. punktu przerwa-nia (cancellation point), tj. wywołania określonych funkcji systemowych (np. sleep, read).Standard POSIX określa, które funkcje muszą, a które mogą być punktami przerwania, defi-niuje także dodatkowo pthread testcancel(void). Pełna lista funkcji znajduje się w rozdzia-le [http://www.opengroup.org/onlinepubs/000095399/functions/xsh chap02 09.html 2.9.5 ThreadCancellation]);

Ustawienie flagi kontrolującej możliwość przerwania wątku wykonuje funkcja pthread setcancelstate,akceptuje dwie wartości:

• PTHREAD CANCEL ENABLE — przerwanie możliwe;

23

3.5. PRZERYWANIE WĄTKÓW

• PTHREAD CANCEL DISABLE — przerwanie niemożliwe; jeśli jednak wystąpi żądanie przerwania, faktten jest pamiętany i gdy stan flagi zmieni się na PTHREAD CANCEL ENABLE wątek zostanie prze-rwany.

Wybór sposobu przerywania umożliwia funkcja pthread setcanceltype, która akceptuje dwie wartości:

• PTHREAD CANCEL ASYNCHRONOUS — przerwanie asynchroniczne,

• PTHREAD CANCEL DEFERRED — przerwanie opóźnione.

Obie funkcje zmieniają parametry wywołującego je wątku.

3.5.1 Funkcje

• int pthread cancel(pthread t thread)

– przerwanie wskazanego wątku

• int pthread setcancelstate(int state, int *oldstate)

– ustawia możliwość przerwania i zwraca poprzednią wartość

• int pthread setcanceltype(int type, int *oldtype)

– ustawia sposób przerwania i zwraca poprzednią wartość

• void pthread testcancel(void)

– punkt przerwania

3.5.2 Przykład

Przykładowy program uruchamia trzy wątki z różnymi ustawieniami dotyczącymi przerywania:

1. dopuszcza przerwanie asynchroniczne,

2. dopuszcza przerwanie opóźnione,

3. przez pewien czas w ogóle blokuje przerwania.

⇒ Przejdź do przykładowego programu nr 7.

Przykładowe wyjście:

$ ./przykladuruchomiono wątek #0 (przerwanie asynchroniczne)#0: wysyłanie sygnału przerwania do wątku#0: wysłano, oczekiwanie na zakończenieuruchomiono wątek #2 (przez 2 sekundy nie można przerwać)funkcja finalizująca dla wątku #0#0: wątek zakończony#1: wysyłanie sygnału przerwania do wątku#1: wysłano, oczekiwanie na zakończenieuruchomiono wątek #1 (przerwanie opóźnione)funkcja finalizująca dla wątku #1#1: wątek zakończony#2: wysyłanie sygnału przerwania do wątku#2: wysłano, oczekiwanie na zakończeniewątek #2 można już przerwaćfunkcja finalizująca dla wątku #2#2: wątek zakończony

24

3.6. PTHREADS I FORKOWANIE

3.6 Pthreads i forkowanie

Biblioteka zarządza trzema listami funkcji, które są wykonywane przy forkowaniu procesu. Jedna listaprzechowuje adresy funkcji wywoływanych przed właściwym uruchomieniem funkcji fork, dwie kolejnezawierają funkcje wykonywane tuż po zakończeniu fork, osobno w procesie rodzica i potomnym.

Funkcja pthread atfork służy do dodawania do list funkcji użytkownika; można podawać pustewskaźniki.

Funkcje wykonywane po forku są wykonywane w kolejności zgodnej z dodawaniem ich do list, nato-miast przed forkiem są uruchamiane w kolejności odwrotnej.

Zastosowaniem tego mechanizmu może być ponowna inicjalizacja wątków w procesie potomnym.Przede wszystkim przy forkowaniu w procesie potomnym działa tylko jeden wątek — główny wątek, wy-konujący funkcję main. Ponadto konieczna jest ponowna inicjalizacja różnych obiektów synchronizujących(np. mutexów), bowiem — jak wspomniano we wstępie — samo skopiowanie pamięci jest niewystarcza-jącego do utworzenia w pełni funkcjonalnej kopii takiego obiektu.

3.6.1 Funkcje

• int pthread atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))

– prepare — funkcja wykonywana przed fork()

– parent — funkcja wykonywana po fork() w procesie rodzica

– child — funkcja wykonywana po fork() w procesie potomnym

3.6.2 Przykład

W programie proces potomny odtwarza jeden działający wątek.

⇒ Przejdź do przykładowego programu nr 18.

Wyjście:

$ ./przykladpoczątek programutworzenie 3 wątków w procesie 8228uruchomiono wątek #1wątek #1 w procesie #8228uruchomiono wątek #2wątek #2 w procesie #8228uruchomiono wątek #3wątek #3 w procesie #8228wątek #1 w procesie #8228wątek #2 w procesie #8228wątek #3 w procesie #8228fork => 8232tworzenie 3 wątków w procesie 8232fork => 0uruchomiono wątek #1wątek #1 w procesie #8232uruchomiono wątek #2wątek #2 w procesie #8232uruchomiono wątek #3wątek #3 w procesie #8232wątek #1 w procesie #8228wątek #3 w procesie #8228wątek #2 w procesie #8228

25

3.7. STOPIEŃ WSPÓŁBIEŻNOŚCI

wątek #1 w procesie #8232wątek #2 w procesie #8232wątek #3 w procesie #8232wątek #1 w procesie #8228wątek #2 w procesie #8228wątek #3 w procesie #8228wątek #1 w procesie #8232wątek #2 w procesie #8232wątek #3 w procesie #8232wątek #1 w procesie #8228wątek #3 w procesie #8228wątek #2 w procesie #8228

3.7 Stopień współbieżności

Dostępne jeśli biblioteka implementuje opcję XSI .Stopień współbieżności jest podpowiedzią (hint) dla biblioteki i ma znaczenie, jeśli wątki pthreads

są uruchamiane na mniejszej liczbie wątków systemowych. Wówczas podpowiedź określa na ilu rzeczywi-stych wątkach zależy programowi.

W Linuxie jeden wątek pthreads odpowiada jednemu wątkowi systemowemu, więc ten parametr niema żadnego znaczenia.

3.7.1 Funkcja

• int pthread setconcurrency(int new level)

– ustawia nowy stopień współbieżności; jeśli 0, przyjmowany jest domyślny

• int pthread getconcurrency(void)

– odczyt

3.8 Czas procesora zużyty przez wątek

Jeśli system implementuje timery (TMR) i rozszerzenie pthreads (TCT) dostępna jest funkcjapthread getcpuclockid, zwracająca identyfikator zegara, który odmierza czas procesora zużyty przezwątek. Zdefiniowana jest wówczas także stała w time.h CLOCK THREAD CPUTIME ID, która odpowiadaidentyfikatorowi zegara dla wywołującego wątku.

Makrodefinicja POSIX THREAD CPUTIME informuje o istnieniu rozszerzenia.Do odczytania czasu na podstawie identyfikatora zegara służy funkcja clock gettime (z time.h).

3.8.1 Funkcja

• int pthread getcpuclockid(pthread t id, clockid t *clock id)

– odczyt identyfikatora zegara

3.8.2 Szkic użycia

\begin{enumerate}

\item include <pthread.h>\item include <time.h>\end{enumerate}

26

3.8. CZAS PROCESORA ZUŻYTY PRZEZ WĄTEK

pthread_t id_watku;

struct timespec czas; // z time.hclock_t id_zegara; // z time.h

\begin{enumerate}

\item ifdef _POSIX_THREAD_CPUTIME\end{enumerate}

if (pthread_getcpuclockid(id_watku, &id_zegara) == 0) {if (clock_gettime(id_zegara, &czas) == 0) {printf("czas procesora: %ld.%03ld ms\n",czas.tv_sec,// tv_sec - sekundyczas.tv_nsec/1000000 // tv_nsec - nanosekundy);}else/* błąd */}else/* błąd */\begin{enumerate}

\item else\item error "pthread_getcpuclockid niedostępne w tym systemie"\item endif\end{enumerate}

3.8.3 Przykład

⇒ Przejdź do przykładowego programu nr 14.

Wynik na maszynie dwuprocesorowej:

$ ./przykladpoczątek programu, uruchomianie zostanie 10 wątkówwątek #0 uruchomiony, dwa razy wykona 86832212 pustych pętliwątek #7 uruchomiony, dwa razy wykona 8298184 pustych pętliwątek #9 uruchomiony, dwa razy wykona 67891648 pustych pętliwątek #5 uruchomiony, dwa razy wykona 27931234 pustych pętliwątek #8 uruchomiony, dwa razy wykona 23876946 pustych pętliwątek #3 uruchomiony, dwa razy wykona 52231547 pustych pętliwątek #6 uruchomiony, dwa razy wykona 16183104 pustych pętliwątek #4 uruchomiony, dwa razy wykona 87068047 pustych pętliwątek #1 uruchomiony, dwa razy wykona 59202170 pustych pętliwątek #2 uruchomiony, dwa razy wykona 48470151 pustych pętlipo około sekundzie wątki zużyły:* #0: 209ms* #1: 138ms* #2: 119ms* #3: 125ms

27

3.8. CZAS PROCESORA ZUŻYTY PRZEZ WĄTEK

* #4: 209ms* #5: 67ms* #6: 41ms* #7: 17ms* #8: 59ms* #9: 154mswątek #7 zakończony, zużył 39ms czasu procesorawątek #6 zakończony, zużył 80ms czasu procesorawątek #8 zakończony, zużył 117ms czasu procesorawątek #5 zakończony, zużył 135ms czasu procesorawątek #2 zakończony, zużył 232ms czasu procesorawątek #3 zakończony, zużył 251ms czasu procesorawątek #1 zakończony, zużył 285ms czasu procesorawątek #9 zakończony, zużył 323ms czasu procesorawątek #0 zakończony, zużył 423ms czasu procesorawątek #4 zakończony, zużył 418ms czasu procesora

główny wątek zużył 0ms czasu procesoraproces zużył 2307ms czasu procesora

28

Rozdział 4

Synchronizacja

29

Pthreads udostępnia kilka sposobów synchronizacji między wątkami:

• podstawowe

– Mutexy (blokada na wyłączność)

– Zmienne warunkowe (condition variable)

– Oczekiwanie na zakończenie wątku

• opcjonalne

– Blokady zapis/odczyt (rwlock)

– Bariery

– Wirujące blokady (spinlock)

Na tej liście nie ma semaforów, ponieważ zostały zdefiniowane we wcześniejszej wersji standardu POSIX —właściwie istniały wcześniej, jako jeden ze standardowych mechanizmów IPC .

Jeśli biblioteka implementuje opcję TSH (Thread Process-Shared Synchronization), wówczas możliwastaje się synchronizacja między wątkami różnych procesów przy użyciu mutexów, zmiennych warunko-wych, blokad odczyt/zapis i barier.

30

4.1. MUTEXY

4.1 Mutexy

Mutex (MUTual EXclusion, wzajemne wykluczanie) jest blokadą, którą może uzyskać tylko jedenwątek. Mutexy służą głównie do realizacji sekcji krytycznych , czyli bezpiecznego w sensie wielowątkowymdostępu do zasobów współdzielonych.

Schemat działania na mutexach jest następujący:

1. pozyskanie blokady

2. modyfikacja lub odczyt współdzielonego obiektu

3. zwolnienie blokady

Mutex w pthreads jest opisywany przez strukturę typu pthread mutex t, zaś jego atrybutypthread mutexattr t.

4.1.1 Inicjalizacja i zwalnianie mutexu

Zmienna typu pthread mutex t może zostać zainicjowana na dwa sposoby:

• poprzez przypisanie symbolu PTHREAD MUTEX INITIALIZER;

• przez wywołanie funkcji pthread mutex init, która umożliwia również podanie atrybutów blokady.

Każdy mutex, bez względu na sposób inicjalizacji, musi zostać zwolniony funkcjapthread mutex destroy. Implementacja biblioteki może bowiem PTHREAD MUTEX INITIALIZER realizo-wać poprzez wywołanie jakiejś funkcji, która np. alokuje pamięć i nie zwolnienie mutexu doprowadzi dowycieku pamięci.

Typy

• pthread mutex t

– mutex

Funkcje

• int pthread mutex create(pthread mutex t *mutex, const pthread mutexattr t *attr)

– inicjacja mutexa, wskaźnik na atrybuty attr może być pusty

• int pthread mutex destroy(pthread mutex t *mutex)

– zwolenienie mutexu

Przykład

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/* lub */

pthread_mutexattr_t attr;pthread_mutexattr_init(&attr); /* inicjalizacja atrybutów mutexa */pthread_mutex_init(&mutex, &attr); /* inicjalizacja mutexa */...pthread_mutex_destroy(&mutex); /* zwolnienie zasobów związanych z mutexem */

31

4.1. MUTEXY

4.1.2 Pozyskiwanie i zwolnienie blokady

Pozyskanie blokady umożliwiają trzy funkcje:

1. pthread mutex lock,

2. pthread mutex trylock,

3. pthread mutex timedlock.

Jeśli żaden inny wątek nie posiada blokady, działają identycznie — tzn. blokada jest przyznawana wywo-łującemu wątkowi. Różnią się zachowaniem w przypadku niemożności uzyskania blokady:

1. pthread mutex lock — oczekiwanie w nieskończoność, aż blokada zostanie zwolniona przez innywątek;

2. pthread mutex trylock — sterowanie wraca natychmiast, zwracając kod EBUSY;

3. pthread mutex timedlock — oczekiwanie ograniczone czasowo, jeśli czas minie, zwraca kodETIMEDOUT.

Wątek musi zwolnić blokadę funkcją pthread unlock.Funkcja pthread mutex timedlock jest dostępna, gdy system implementuje rozszerzenie TMO. W od-

różnieniu od innych funkcji operujących na czasach oczekiwania (np. select dla plików), w których podajesię ile czasu ma upłynąć od chwili wywołania funkcji, w pthreads podawany jest czas bezwzględny.

Funkcje

• int pthread mutex lock(pthread mutex t *mutex)

• int pthread trylock(pthread mutex t *mutex)

• int pthread timedlock(pthread mutex t *mutex, const struct timespec *timeout)

Szkic użycia

#include <pthread.h>#include <errno.h>#include <time.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/* ... */pthread_mutex_lock(&mutex);// działania na obiekcie współdzielonympthread_mutex_unlock(&mutex);

/* ... */switch (pthread_mutex_try_lock(&mutex)) {case 0:// działania na obiekcie współdzielonympthread_mutex_unlock(&mutex);break;

case EBUSY:puts("Blokadę posiada inny wątek");break;

default:

32

4.1. MUTEXY

puts("Inny błąd");break}

/* ... */struct timespec timeout;clock_gettime(CLOCK_REALTIME, &timeout); // pobranie bieżącego czasutimeout.tv_sec += 2; // zwiększenie liczby sekund o 2

switch (pthread_mutex_timedlock(&mutex, &timeout)) {case 0:puts("Blokada pozyskana przed upływem 2 sekund");// działania na obiekcie współdzielonympthread_mutex_unlock(&mutex);break;

case ETIMEDOUT:puts("Upłynęły 2 sekundy");break;

default:puts("Inny błąd");break;}

Przykład

Program demonstruje sekcję krytyczną z użyciem mutexów. Jeśli przy kompilacji zdefiniowane zo-stanie BLOKADA, wówczas mutex blokuje dostęp do zmiennej, która jest inkrementowana określoną liczbęrazy przez każdy z wątków. W przeciwnym razie wątki zmieniają ją bez żadnej synchronizacji, co możeprowadzić do błędu — w tym przypadku do niepoprawnego zliczenia.

⇒ Przejdź do przykładowego programu nr 15.

Przykładowe wyjście (z błędem):

$ ./przykladlicznik = 0licznik = 9968, spodziewana wartość = 10000 BŁĄD!!!

4.1.3 Typy mutexów

Opcja XSI . Jednym z atrybutów mutexu jest jego typ, czy też rodzaj:

1. zwykły (normal),

2. rekursywny (recursive),

3. bezpieczny (error check).

Na poziomie współpracy między wątkami rodzaj mutexu nie ma znaczenia, objawia się dopiero w obrębiejednego wątku w dwóch sytuacjach:

• ponowna próba pozyskania blokady,

• próba zwolnienia już zwolnionej blokady.

33

4.1. MUTEXY

Ponowne blokowanie

Można wyobrazić sobie sytuację (raczej prawdopodobną), gdy w programie istnieje funkcja pomocni-cza, wykorzystywana przez wątki, która zakłada blokadę na pewne dane. Problem pojawia się w chwili,gdy wątek już pozyskał blokadę i wywołuje taką funkcję. Wówczas z punktu widzenia blokady wątekpróbuje wykonać następującą sekwencję:

pthread_mutex_lock(&mutex); // (1)pthread_mutex_lock(&mutex); // (2) - w funkcji pomocniczej/* ... */pthread_mutex_unlock(&mutex) // (3) - w funkcji pomocniczejpthread_mutex_unlock(&mutex) // (4)

• W przypadku mutexu zwykłego wykona się pierwsza funkcja pthread mutex lock (1), zaś nadrugim jej wywołaniu (2) wątek zatrzyma się, oczekując na zwolnienie blokady — co nigdy nienastąpi, bowiem sterowanie nie dojdzie do wiersza (3) ani (4). Występuje zakleszczenie.

• W przypadku mutexu rekursywnego wykonają się wszystkie funkcje związane z blokadą. Mu-tex tego typu posiada dodatkowy licznik zagnieżdżeń, który z każdym wywołaniem funkcjipthrad mutex lock jest zwiększany, natomiast wywołanie pthread mutex unlock zmniejsza go —gdy osiągnie zero, blokada jest zwalniana.

• W przypadku mutexu bezpiecznego drugie wywołanie pthread mutex lock zwróci kod błęduEDEADLK, oznaczający, że wątek już posiada tę blokadę.

Ponowne odblokowanie

Jeśli blokada jest zwolniona ponowne wywołanie pthread unlock mutexy bezpieczne i rekursywnyzwracają błąd. Zachowanie zwykłego mutexu jest nieokreślone!

Przykład

Ilustracja różnicy w działaniu mutexów.

⇒ Przejdź do przykładowego programu nr 8.

• Wynik dla mutexu zwykłego — wystąpiło zakleszczenie, program ”zawiesił się” i musiał zostaćprzerwany ręcznie:

$ ./przyklad 0mutex typu PTHREAD_MUTEX_NORMALprzed wykonaniem pthread_mutex_lock (1)... wykonano pthread_mutex_lock (1)przed wykonaniem pthread_mutex_lock (2)\textbf{^C}

• Wynik dla mutexu sprawdzającego — nie dopuszczono do zakleszczenia:

$ ./przyklad 1mutex typu PTHREAD_MUTEX_ERRORCHECKprzed wykonaniem pthread_mutex_lock (1)... wykonano pthread_mutex_lock (1)przed wykonaniem pthread_mutex_lock (2)\textbf{pthread_mutex_lock (2): Resource deadlock avoided}

• Wynik dla mutexu rekursywnego — blokada jest pozyskiwana wielokrotnie:

34

4.1. MUTEXY

$ ./przyklad 2mutex typu PTHREAD_MUTEX_RECURSIVEprzed wykonaniem pthread_mutex_lock (1)... wykonano pthread_mutex_lock (1)przed wykonaniem pthread_mutex_lock (2)... wykonano pthread_mutex_lock (2)przed wykonaniem pthread_mutex_unlock (2)... wykonano pthread_mutex_unlock (2)przed wykonaniem pthread_mutex_unlock (1)... wykonano pthread_mutex_unlock (1)program zakończony

4.1.4 Atrybuty mutexu

Inicjalizacja i usuwanie

Typy

• pthread mutexattr t

Funkcje

• int pthread mutexattr destroy(pthread mutexattr t *attr)

• int pthread mutexattr init(pthread mutexattr t *attr)

Typ mutexu

Opisane wyżej

Funkcje

• int pthread mutexattr settype(pthread mutexattr t *attr, int type)

• int pthread mutexattr gettype(const pthread mutexattr t *atter, int *type)

Współdzielenie mutexu z innymi procesami

Patrz rozdział synchronizacja między wątkami różnych procesów.

Funkcje

• int pthread mutexattr setpshared(pthread mutexattr t *attr, int pshared)

• int pthread mutexattr getpshared(const pthread mutexattr t *attr, int *pshared)

Zmiana priorytetu wątku posiadającego blokadę

Dostępne, gdy istnieje rozszerzenie TPP (oraz TPI).Wartość atrybutu decyduje o strategii wykonywania programu, gdy wiele wątków o różnych prioryte-

tach stara się o uzyskanie blokady. Atrybut może mieć wartości:

1. PTHREAD PRIO NONE,

2. PTHREAD PRIO PROTECT,

3. PTHREAD PRIO INHERIT (opcja TPI).

35

4.1. MUTEXY

W przypadku PTHREAD PRIO NONE priorytet wątku, który pozyskuje blokadę nie zmienia.W dwóch pozostałych przypadkach z mutexem powiązany zostaje pewien priorytet i gdy wątek uzyska

blokadę, wówczas jego priorytet jest podbijany do wartość z mutexu (o ile oczywiście był wcześniej niższy).Innymi słowy w obrębie sekcji krytycznej wątek może działać z wyższym priorytetem.

Sposób ustalania priorytetu mutexu zależy od atrybutu:

• PTHREAD PRIO INHERIT — wybierany jest maksymalny priorytet spośród wątków oczekujących nauzyskanie danej blokady;

• PTHREAD PRIO PROTECT — priorytet jest ustalany przez programistę funkcjąpthread mutexattr setprioceiling lub pthread mutex setprioceiling (opisane w następnejsekcji).

Dodatkowo jeśli wybrano wartość PTHREAD PRIO PROTECT, wówczas wszelkie próby założenia blokadyfunkcjami pthread mutex XXXlock z poziomu wątków o priorytecie niższym niż ustawiony dla mutexanie powiodą się — zostanie zwrócona wartość błędu EINVAL.

Funkcje

• int pthread mutexattr setprotocol(pthread mutexattr t *attr, int protocol)

• int pthread mutexattr getprotocol(const pthread mutexattr t *attr, int *protocol)

Minimalny priorytet wątku zakładające blokadę

Dostępne w opcji TPP. Funkcje ustalają/odczytują bieżący priorytet związany z mutexem.

Funkcje działające na atrybutach

• int pthread mutexattr setprioceiling(pthread mutexattr t *attr, int prioceiling)

• int pthread mutexattr getprioceiling(const pthread mutexattr t *attr, int *prioceiling)

Funkcje działające bezpośrednio na mutexie

• int pthread mutex setprioceiling(pthread mutex t *attr, int prioceiling)

• int pthread mutex getprioceiling(const pthread mutex t *attr, int *prioceiling)

36

4.2. ZMIENNE WARUNKOWE

4.2 Zmienne warunkowe

Zmienna warunkowa (condition variable) jest jednym ze sposobów synchronizacji między wątka-mi — polega na przesłaniu sygnału z jednego wątku do innych wątków, które na ten sygnał oczekują.

Prościej rzecz ujmując jeden lub kilka wątków może oczekiwać na zajście jakiegoś warunku, innywątek, gdy go spełni, sygnalizuje właśnie poprzez zmienną warunkową ten fakt jednemu lub wszystkimoczekującym. We wzorcu producent-konsument występuje właśnie taka sytuacja: konsument (jeden lubwięcej) czeka na pojawienie się obiektów od producenta (jednego lub więcej).

Zmienna warunkowa jest zawsze używana z mutexem.Typem danych, który opisuje zmienną warunkową jest pthread cond t.

4.3 Schemat użycia zmiennej warunkowej podczas oczekiwania

1. pozyskaj blokadę (mutex)

2. sprawdź, czy warunek zaszedł

3. jeśli tak, zwolnij blokadę

4. w przeciwnym razie oczekuj na sygnał (w tym miejscu blokada jest automatycznie zwalniana)

5. * sygnał nadszedł, przejdź do punktu 2 (w tym miejscu blokada jest automatycznie ponowniepozyskiwana)

Co w języku C wygląda mniej więcej tak:

pthread_mutex_lock(&mutex)do {if (warunek spełniony) {/* ... */break;}elsepthread_cond_wait(&cond, &mutex);} while (1)pthread_mutex_unlock(&mutex);

4.4 Inicjalizacja zmiennej warunkowej

Funkcją pthread cond init inicjuje zmienną warunkową, umożliwia również przypisanie atrybutów.Istnieje możliwość statycznej inicjalizacji wartością PTHREAD COND INITIALIZER.

Każda zmienna warunkowa, bez względu na sposób inicjalizacji, musi zostać zwolniony funkcjapthread cond destroy. Implementacja biblioteki może bowiem PTHREAD COND INITIALIZER realizowaćpoprzez wywołanie jakiejś funkcji, która np. alokuje pamięć i nie zwolnienie zmiennej doprowadzi dowycieku pamięci.

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;pthread_cond_attr_t attr;

/* ... */pthread_cond_init(&cond, NULL); /* inicjalizacja zmiennej warunkowej z atrybutami domyślnymi */

/* ... */pthread_condattr_init(&attr); /* inicjalizacja atrybutów zmiennej */pthread_cond_init(&cond, &attr); /* inicjalizacja zmiennej warunkowej z atrybutami użytkownika */

37

4.5. ATRYBUTY

/* ... */pthread_cond_destroy(&cond); /* skasowanie zmiennej warunkowej */pthread_condattr_destroy(&attr); /* oraz atrybutów */

4.4.1 Typy

• pthread cond t

– zmienna warunkowa

• pthread condattr t

– atrybuty zmiennej warunkowej

4.4.2 Funkcje

• int pthread(pthread cond t *cond, cond pthread condattr t *attr)

– inicjacja zmiennej warunkowej, wskaźnik na atrybuty attr może być pusty

• int pthread(pthread cond t *cond)

– zwolenie zmiennej warunkowej

4.5 Atrybuty

Zmienna warunkowa może mieć dwa atrybuty, zależnie od rozszerzeń:

• THS — czy zmienna warunkowa może być współdzielona między procesami (domyślnie nie);

• CT — ustawienie identyfikatora zegara, który jest używany przy odmierzaniu czasu w funkcjipthread cond timedwait

4.5.1 Typy

• pthread condattr t

– atrybuty zmiennej warunkowej

4.5.2 Funkcje

• int pthread condattr init(pthread condattr t *attr)

– inicjacja atrybutów zmiennej warunkowej

• int pthread condattr destroy(pthread condattr t *attr)

– zwolenienie atrybutów zmiennej warunkowej

• int pthread condattr setpshared(pthread condattr t *attr, int pshared)

– ustawienie flagi współdzielenia z innymi procesami; pshared ma wartośćPTHREAD PROCESS SHARED lub PTHREAD PROCESS PRIVATE (domyślnie)

• int pthread condattr getpshared(pthread condattr t *attr, int *pshared)

– odczyt flagi

• int pthread condattr setclock(pthread condattr t *attr, clockid t clock id)

38

4.6. SYGNALIZOWANIE I ROZGŁASZANIE

– ustawienie identyfikatora zegara

• int pthread condattr getclock(pthread condattr t *attr, clockid t *clock id)

– odczyt identyfikatora

4.6 Sygnalizowanie i rozgłaszanie

Wątek, który zmienił warunek informuje o tym fakcie oczekujące wątki na dwa sposoby:

• sygnalizując (pthread cond signal) — sygnał trafia do jednego z oczekujących wątków, przyczym nie jest określone do którego;

• rozgłaszając (pthread cond broadcast) — sygnał trafia do wszystkich oczekujących wątków.

4.6.1 Funkcje

• int pthread cond signal(pthread cond t *cond)

• int pthread cond broadcast(pthread cond t *cond)

4.7 Oczekiwanie

Oczekiwanie na zmienną warunkową umożliwiają dwie funkcje:

1. pthread cond wait — oczekuje w nieskończoność na sygnał,

2. pthread cond timedwait — oczekuje przez ograniczony czas.

Sposób obsługi czasu w pthreads został opisany dokładnie przy okazji pthread mutex timedwait (Po-zyskiwanie i zwolnienie blokady).

4.7.1 Funkcje

• int pthread cond wait(pthread cond t *cond, pthread mutex t* mutex)

• int pthread cond timedwait(pthread cond t *cond, pthread mutex t* mutex, const struct timespec*abstime)

4.8 Przykład

⇒ Przejdź do przykładowego programu nr 9.

Przykładowe wyjście:

$ ./przykladpoczątek programuuruchomiono wątek #5wątek #5 oczekuje na sygnał...uruchomiono wątek #3wątek #3 oczekuje na sygnał...uruchomiono wątek #1wątek #1 oczekuje na sygnał...uruchomiono wątek #4wątek #4 oczekuje na sygnał...uruchomiono wątek #2

39

4.8. PRZYKŁAD

wątek #2 oczekuje na sygnał...pthread_cond_signal - sygnalizacja... wątek #5 otrzymał sygnał!wątek #5 oczekuje na sygnał...pthread_cond_broadcast - rozgłaszanie... wątek #3 otrzymał sygnał!wątek #3 oczekuje na sygnał...... wątek #1 otrzymał sygnał!wątek #1 oczekuje na sygnał...... wątek #4 otrzymał sygnał!wątek #4 oczekuje na sygnał...... wątek #2 otrzymał sygnał!wątek #2 oczekuje na sygnał...... wątek #5 otrzymał sygnał!wątek #5 oczekuje na sygnał...koniec programu

40

4.9. WSTĘP

4.9 Wstęp

Mutexy czy wirujące blokady umożliwiają ochronę współdzielonych zasobów jednakowo traktującwątki zmieniające ten obiekt jak i wątki jedynie czytające — dopuszczając do obiektu tylko jeden wątek.

Blokady zapis/odczyt (rwlocks) rozróżniają cel dostępu do obiektu współdzielonego — wątek możezałożyć blokadę do odczytu (rdlock) lub do zapisu (wrlock). Dowolna liczba wątków może mieć jedno-czesny dostęp do obiektu chronionego, jeśli tylko zakładają blokadę do odczytu, natomiast dokładniejeden wątek ma dostęp do obiektu, gdy założy blokadę do zapisu.

4.10 Inicjalizacja i destrukcja

Blokadę tworzy funkcja pthread rwlock init, natomiast niszczy pthread rwlock destroy.

4.10.1 Typy

• pthread rwlock t

• pthread rwlockattr t

4.10.2 Funkcje

• pthread rwlock init

• pthread rwlock destroy

4.11 Atrybuty blokady

Atrybuty blokady tworzy funkcja pthread rwlockattr init, natomiast niszczypthread rwlockattr destroy.

Jeśli biblioteka implementuje opcję THS, wówczas blokada ma tylko jeden parametr: flagęwspółdzielenia między procesami, którą ustawia pthread rwlockattr setpshared, zaś odczytujepthread rwlockattr getpshared.

4.11.1 Typy

• pthread rwlockattr t

4.11.2 Funkcje

• pthread rwlockattr init(pthread rwlockattr t *attr)

– incjalizacja

• pthread rwlockattr destroy(pthread rwlockattr t *attr)

– zniszczenie

• pthread rwlockattr setpshared(pthread rwlockattr t *attr, int pshared)

– ustawienie flagi, pshared ma wartość PTHREAD PROCESS PRIVATE lubPTHREAD PROCESS SHARED

• pthread rwlockattr getpshared(const pthread rwlockattr t *attr, int pshared

– odczyt flagi

41

4.12. BLOKADY DO ODCZYTU

4.12 Blokady do odczytu

4.12.1 Funkcje

• pthread rwlock rdlock(pthread rwlock t *rwlock)

– oczekiwanie na pozyskanie blokady w nieskończoność

• pthread rwlock tryrdlock(pthread rwlock t *rwlock)

– bez oczekiwania na pozyskanie blokady

• pthread rwlock timedrdlock(pthread rwlock t *rwlock, const struct timespec *abs timeout)

– oczekiwanie na pozyskanie blokady ograniczone czasowo (dostępne jeśli biblioteka implemen-tuje opcję TMO)

4.13 Blokady do zapisu

4.13.1 Funkcje

• pthread rwlock wrlock(pthread rwlock t *rwlock)

– oczekiwanie na pozyskanie blokady w nieskończoność

• pthread rwlock trywrlock(pthread rwlock t *rwlock)

– bez oczekiwania na pozyskanie blokady

• pthread rwlock timedwrlock(pthread rwlock t *rwlock, const struct timespec *abs timeout)

– oczekiwanie na pozyskanie blokady ograniczone czasowo (dostępne jeśli biblioteka implemen-tuje opcję TMO)

4.14 Zwalnianie blokady

Niezależnie od rodzaju pozyskanej blokady, wątek zwalnia ją funkcją pthread rwlock unlock.

4.14.1 Funkcje

• int pthread rwlock unlock(pthread rwlock t *rwlock)

4.15 Przykład

Przykładowy program tworzy kilka wątków piszących, a więc zakładających blokady do zapisu, orazwięcej wątków czytających, zakładających blokady do odczytu.

⇒ Przejdź do przykładowego programu nr 16.

Przykładowy wynik:

$ ./przykladpisarz #0 czeka na dostęppisarz #0 ustawia nową wartośćpisarz #1 czeka na dostępczytelnik #0 czeka na dostępczytelnik #1 czeka na dostępczytelnik #3 czeka na dostęp

42

4.15. PRZYKŁAD

czytelnik #2 czeka na dostępczytelnik #4 czeka na dostęppisarz #0 zwalnia blokadępisarz #1 ustawia nową wartośćpisarz #1 zwalnia blokadęczytelnik #0 odczytuje wartośćczytelnik #4 odczytuje wartośćczytelnik #1 odczytuje wartośćczytelnik #3 odczytuje wartośćczytelnik #2 odczytuje wartośćczytelnik #4 zwalnia blokadęczytelnik #1 zwalnia blokadęczytelnik #2 zwalnia blokadęczytelnik #0 zwalnia blokadęczytelnik #3 zwalnia blokadęczytelnik #3 czeka na dostępczytelnik #3 odczytuje wartośćczytelnik #0 czeka na dostępczytelnik #0 odczytuje wartośćczytelnik #2 czeka na dostępczytelnik #2 odczytuje wartośćczytelnik #1 czeka na dostępczytelnik #1 odczytuje wartośćczytelnik #4 czeka na dostępczytelnik #4 odczytuje wartośćczytelnik #2 zwalnia blokadęczytelnik #3 zwalnia blokadęczytelnik #4 zwalnia blokadęczytelnik #0 zwalnia blokadęczytelnik #1 zwalnia blokadępisarz #0 czeka na dostęppisarz #0 ustawia nową wartośćczytelnik #2 czeka na dostępczytelnik #3 czeka na dostępczytelnik #4 czeka na dostępczytelnik #1 czeka na dostępczytelnik #0 czeka na dostęppisarz #0 zwalnia blokadęczytelnik #2 odczytuje wartośćczytelnik #4 odczytuje wartośćpisarz #1 czeka na dostępczytelnik #0 odczytuje wartośćczytelnik #3 odczytuje wartośćczytelnik #1 odczytuje wartośćczytelnik #1 zwalnia blokadęczytelnik #3 zwalnia blokadęczytelnik #0 zwalnia blokadęczytelnik #2 zwalnia blokadęczytelnik #4 zwalnia blokadępisarz #1 ustawia nową wartość

43

4.16. WSTĘP

4.16 Wstęp

Bariera jest mechanizmem synchronizacji grupy wątków. Wątki po dojściu bo bariery są wstrzymy-wane do czasu, aż ostatni jej nie osiągnie — wówczas wszystkie są kontynuowane. Z barierą związana jestliczba większa od zera określająca ile wątków wchodzi w skład grupy.

Gdy bariera jest osiągana przez wszystkie wątki, jej stan (licznik) jest automatycznie inicjowany, nataką wartość, jaką ustawiło ostatnie wywołanie pthread barrier init.

4.17 Inicjalizacja bariery

Inicjalizację bariery wykonuje funkcja pthread barrier init, usuwa zaś funkcjapthread barrier destroy. Bariera może mieć dodatkowe atrybut.

4.17.1 Typy

• pthread barrier t

– bariera

• pthread barrierattr t

– atrybuty bariery

4.17.2 Funkcje

• int pthread barrier init(pthread barrier t *barrier, pthread barrierattr t* attr,unsigned int count)

– inicjacja bariery, count jest liczbą wątków w grupie, attr opcjonalne atrybuty

• int pthread barrier destroy(pthread barrier t *barrier)

– usunięcie bariery

4.18 Atrybuty bariery

Gdy biblioteka implementuje opcję TSH , wówczas można ustalić, czy bariery mogą być współdzielonemiędzy procesami — domyślnie nie.

4.18.1 Funkcje

• int pthread barrier init(pthread barrierattr t *attr)

– inicjacja atrybutów bariery

• int pthread barrierattr destroy(pthread barrierattr t *attr)

– usunięcie atrybutów

• int pthread barrierattr setpshared(pthread barrierattr t *attr, int pshared)

– ustawienie flagi współdzielenia z innymi procesami; pshared ma wartośćPTHREAD PROCESS SHARED lub PTHREAD PROCESS PRIVATE (domyślnie)

• int pthread barrierattr getpshared(pthread barrierattr t *attr, int *pshared)

– odczytanie flagi

44

4.19. BARIERA

4.19 Bariera

Wywołanie funkcji pthread barrier wait jest traktowane jako dojście do bariery — powoduje zwięk-szenie licznika związanego z barierą.

Gdy bariera zostanie osiągnięta przez wszystkie wątki, funkcja w jednym wątku (standard nie określaw którym) zwraca specjalną wartość PTHREAD BARRIER SERIAL THREAD, pozostałe wartość 0.

4.19.1 Funkcje

• int pthread barrier wait(pthread barrier t *barrier)

4.19.2 Przykład

W programie bariera służy do wstrzymania programu, do czasu aż wszystkie utworzone wątki skończądziałanie.

⇒ Przejdź do przykładowego programu nr 11.

Przykładowe wyjście:

zostanie uruchomionych 10 wątkówwątek #0 rozpoczęty, zostanie wstrzymany na 0 sekundwątek #0 osiągnął barieręwątek #1 rozpoczęty, zostanie wstrzymany na 0 sekundwątek #1 osiągnął barieręwątek #2 rozpoczęty, zostanie wstrzymany na 0 sekundwątek #2 osiągnął barieręwątek #3 rozpoczęty, zostanie wstrzymany na 0 sekundwątek #3 osiągnął barieręwątek #4 rozpoczęty, zostanie wstrzymany na 4 sekundwątek #5 rozpoczęty, zostanie wstrzymany na 4 sekundwątek #6 rozpoczęty, zostanie wstrzymany na 3 sekundwątek #7 rozpoczęty, zostanie wstrzymany na 4 sekundwątek #8 rozpoczęty, zostanie wstrzymany na 4 sekundwątek #9 rozpoczęty, zostanie wstrzymany na 4 sekundwątek główny osiągnął barieręwątek #6 osiągnął barieręwątek #4 osiągnął barieręwątek #5 osiągnął barieręwątek #7 osiągnął barieręwątek #8 osiągnął barieręwszystkie wątki osiągnęły barierę (wątek #9)

45

4.20. WSTĘP

4.20 Wstęp

Wirująca blokada (spinlock) jest rodzajem blokady, w której aktywnie oczekuje się na jej zwolnieniew przypadku, gdy nie może zostać pozyskana. Pod względem semantyki nie różnią się od mutexów, jednakzasadniczo różnią w implementacji i zakresie zastosowania.

Przede wszystkim spinlock zużywa czas procesora, więc jego stosowanie ma sens, gdy współdzielonezasoby nie są zbyt długo blokowane przez inne wątki. Ponadto na systemach wieloprocesorowych unikasię kosztownego przełączania kontekstu.

4.21 Inicjalizacja i zwalnianie

4.21.1 Typy

• pthread spinlock t

4.21.2 Funkcje

• int pthread spin init(pthread spinlock t *lock, int pshared)

– inicjalizacja wirującej blokady; argument pshared przymuje wartościPTHREAD PROCESS PRIVATE lub PTHREAD PROCESS SHARED, jeśli dostępna jest opcja THS —patrz synchronizacja między wątkami różnych procesów

• int pthread spin destroy(pthread spinlock t *lock)

– zniszczenie wirującej blokady

4.22 Pozyskiwanie blokady

4.22.1 Funkcje

• int pthread spin lock(pthread spinlock t *lock)

– założenie blokady, jeśli nie jest to możliwe — oczekiwanie

• int pthread spin trylock(pthread spinlock t *lock)

– założenie blokady, jeśli nie jest to możliwe — zwrócenie kodu błędu EBUSY

4.23 Zwalnianie blokady

4.23.1 Funkcje

• int pthread spin unlock(pthread spinlock t *lock)

– zwolnienie blokady

46

4.24. PRZYKŁAD

Jeśli biblioteka pthreads implementuje opcję TSH (Thread Process-Shared Synchronization), wów-czas możliwa staje się synchronizacja między wątkami różnych procesów przy użyciu:

• mutexów,

• zmiennych warunkowych,

• blokad odczyt/zapis,

• barier.

Domyślnie obiekty synchronizujące są lokalne względem procesu, w ramach którego zostały utworzone.Jeśli są współdzielone z innymi procesami, wówczas można używać adresów obiektów znajdujących sięw segmencie pamięci dzielonej.

UWAGA

Standard nie określa, co się stanie jeśli prywatne obiekty synchronizujące zo-staną użyte przez wątki innego procesu. Np. w Linuxie nie są zgłaszane żadnebłędy, lecz synchronizacja nie funkcjonuje.

To, czy obiekt synchronizujący będzie współdzielony decydują jego atrybuty — ustawiane funkcja-mi int pthread XXXattr setpshared(pthread XXXattr t *attr, int shared) (XXX=mutex, cond,rwlock, barrier), gdzie parametr shared przyjmuje wartości:

• PTHREAD PROCESS PRIVATE (domyślnie) — obiekt prywatny;

• PTHREAD PROCESS SHARED — współdzielony.

4.24 Przykład

Przykładowy program w zależności od argumentów:

1. Tworzy segment pamięci dzielonej, podłącza go do przestrzeni adresowej procesu, w którego obszarzeinicjalizuje mutex i zmienną warunkową na współdzielone (PTHREAD PROCESS SHARED) i oczekuje nawarunek — ustawienie napisu.

2. Podłącza się do już utworzonego segmentu pamięci, ustawia napis i sygnalizuje zmienną warunkowąten fakt.

⇒ Przejdź do przykładowego programu nr 17.

$ ./przykladproces 1id segmentu pamięci dzielonej: 27197465adres przyłączonego segmentu: 0xb76e7000pthread_cond_wait

inny proces ustawił napis: ’czy konie mnie słyszą?’$

47

4.24. PRZYKŁAD

$ ./przyklad 27197465 "czy konie mnie słyszą?"proces 2: segment pamięci dzielonej 27197465adres przyłączonego segmentu: 0xb7727000proces ustawił napis ’czy konie mnie słyszą?’ i wykonał pthread_cond_signal$

48

Rozdział 5

Rozszerzenia

49

5.1. LINUX

5.1 Linux

Sufiksem nazw większości funkcji Linuxa jest np.

5.1.1 Zbiór procesorów, na jakich może uruchomić się wątek

Funkcje umożliwiają ustawienie i odczyt zbioru procesorów na jakich wątek ma działać. (Analogiczneustawienia są możliwe na poziomie procesów).

• pthread setaffinity np (3)

• pthread getaffinity np (3)

• pthread attr getaffinity np (3)

• pthread attr setaffinity np (3)

5.1.2 Funkcje finalizujące i asynchroniczne przerwania

• pthread cleanup push defer np (3) — funkcja działa podobnie, jak pthread cleanup push, z tymże po odłożeniu funkcji na stos ustawia sposób przerwania wątku na opóźniony (jednocześnie zapa-miętując bieżące ustawiania)

• pthread cleanup pop restore np (3) — ściąga za stosu funkcję i ewentulanie uruchamia, odtwarzapoprzedni sposób przerywania

5.1.3 Bieżące atrybuty wątku

Umożliwia odczytanie bieżących atrybutów już uruchomionego wątku.

• pthread getattr np (3)

5.1.4 Oczekiwania na zakończenie wątku

Uzupełnienie mechanizmu oczekiwania na zakończenie wątków (pthread join):

• pthread timedjoin np (3) — oczekiwanie ograniczone czasowo,

• pthread tryjoin np (3) — sprawdzenie, bez oczekiwania, czy wątek się zakończył

5.1.5 Zrzeczenie się czasu procesora

• pthread yield (3) — alias dla standardowego sched yield, czyli zrzeczenia się czasu procesorai oczekiwanie na ponowne jego przyznanie

50

5.2. CYGWIN

5.2 Cygwin

Cygwin definiuje dwie dodatkowe funkcje:

1. pthread suspend(pthread t id) — wstrzymanie wykonywania wskazanego wątku;

2. pthread resume(pthread t id) — wznowienie wykonywania uprzednio wstrzymanego wątku.

51

5.2. CYGWIN

52

Rozdział 6

Przykładowe programy

53

6.1. KOMPILACJA

6.1 Kompilacja

Wszystkie programy zostały skompilowane kompilatorem gcc i uruchomione na Linuxie 2.6, część bezproblemów skompilowała się i uruchomiła w Cygwinie.

Kompilator był wywoływany z następującymi opcjami:

gcc -Wall -pedantic -std=c99 \textbf{-lpthreads} \emph{program.c} -o przyklad

lub

gcc -Wall -pedantic -std=c99 \textbf{-pthread} \emph{program.c} -o przyklad

Niektóre przykłady (wirujące blokady, bariery) muszą być linkowane z librt, czyli konieczna jest opcja-lrt.

Aby skompilować część z nich trzeba ustawić odpowiednie definicje preprocesora, w szczególnościPOSIX C SOURCE na odpowiednią wartość — w przykładach jest to 200809L, dając dostęp do funkcji z

nowszych rewizji standardu POSIX.

6.2 Wykaz przykładów

Program 1 (Tworzenie wątku)

• pthread create• pthread join

Program 2 (Przekazywanie argumentów)

• pthread create• pthread join

Program 3 (Kończenie wątku)

• pthread exit• pthread create• pthread join

Program 4 (Atrybuty wątku)

• pthread attr getdetachstate• pthread attr getguardsize• pthread attr getinheritsched• pthread attr getschedparam• pthread attr getschedpolicy• pthread attr getscope• pthread attr getstackaddr• pthread attr getstacksize• pthread attr init

Program 5 (Stos funkcji finalizujących (cleanup))

• pthread cleanup pop• pthread cleanup push• pthread create

54

6.2. WYKAZ PRZYKŁADÓW

• pthread exit• pthread join

Program 6 (Funkcje wywoływane jednokrotnie)

• pthread once• pthread create• pthread join

Program 7 (Przerywanie wątków)

• pthread cancel• pthread setcancelstate• pthread setcanceltype• pthread testcancel• pthread cleanup push• pthread create• pthread join

Program 8 (Typy mutexów)

• pthread mutexattr settype• pthread mutexattr init• pthread mutex unlock• pthread mutex lock• pthread create• pthread join

Program 9 (Zmienne warunkowe)

• pthread cond wait• pthread cond signal• pthread cond broadcast• pthread mutex lock• pthread mutex unlock• pthread create

Program 10 (Lokalne dane wątku)

• pthread key create• pthread key delete• pthread setspecific• pthread getspecific• pthread create• pthread join

Program 11 (Bariery)

• pthread barrier init• pthread barrier destroy

55

6.2. WYKAZ PRZYKŁADÓW

• pthread barrier wait• pthread create

Program 12 (Rozmiar i adres stosu)

• pthread attr setstacksize• pthread attr getstacksize• pthread attr init• pthread attr destroy• pthread create• pthread join

Program 13 (UNIX-owe sygnały)

• pthread kill• pthread sigmask• pthread create• pthread self

Program 14 (Czas procesora zużyty przez wątek)

• pthread getcpuclockid• clock gettime (nie pthreads)

• pthread create• pthread join

Program 15 (Pozyskiwanie i zwolnienie blokady)

• pthread mutex lock• pthread mutex unlock• pthread mutex init• pthread create• pthread join

Program 16 (Blokady zapis/odczyt)

• pthread rwlock init• pthread rwlock rdlock• pthread rwlock wrlock• pthread rwlock unlock• pthread create

Program 17 (Synchronizacja między wątkami różnych procesów)

• pthread cond init• pthread cond signal• pthread cond wait• pthread condattr init• pthread condattr setpshared• pthread mutex init

56

6.2. WYKAZ PRZYKŁADÓW

• pthread mutex lock• pthread mutex unlock• pthread mutexattr init• pthread mutexattr setpshared

Program 18 (Pthreads i forkowanie)

• pthread atfork• pthread create

Program 19 (Wybór algorytmu szeregowania i ustawienie jego parametrów)

• pthread attr setinheritsched• pthread attr setschedpolicy• pthread attr setschedparam• sched get priority min• sched get priority max• pthread attr init• pthread attr destroy• pthread create• pthread join

57

6.2. WYKAZ PRZYKŁADÓW

Przykład 1

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : h e l l o world z k i l k u wątków∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

/∗ f u n k c j a wykonywana w wątku − nic s p e c j a l n e g o nie r o b i ∗/void∗ watek ( void∗ arg ) {

puts ( ”Witaj w równoległym ś w i e c i e ! ” ) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 5 /∗ l i c z b a wątków ∗/

int main ( ) {pthread t id [N ] ;int i ;

/∗ utworzenie k i l k u wątków wątku ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , NULL) ;t e s t e r r n o ( ”Nie powiodło s i ę p th r ead c r ea t e ” ) ;

}

/∗ oczek iwanie na j e g o zakończen ie ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

}

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

58

6.2. WYKAZ PRZYKŁADÓW

Przykład 3

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : zakończen ie wątku z poziomu f u n k c j i wywływanych w wątku∗ za pomocą∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

void koniec watku ( int l i c z n i k , int l i m i t ) {int i ;for ( i =0; i < l i c z n i k ; i++) putchar ( ’ ’ ) ;p r i n t f ( ” l i c z n i k = %d , l i m i t = %d\n” , l i c z n i k , l i m i t ) ;

i f ( l i c z n i k == l i m i t )/∗ zakończen ie wątku w k t ó r e g o k o n t e k ś c i e wykonywana j e s t ta f u n k c j a ∗/p t h r e a d e x i t (NULL) ;

elsekoniec watku ( l i c z n i k +1, l i m i t ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek ( void∗ arg ) {koniec watku (0 , 5) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t id ;

/∗ utworzenie wątku ∗/errno = pthr ead c r ea t e (&id , NULL, watek , NULL) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

/∗ oczek iwanie na j e g o zakończen ie ∗/errno = p t h r e a d j o i n ( id , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

return EXIT SUCCESS ;}

59

6.2. WYKAZ PRZYKŁADÓW

//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

60

6.2. WYKAZ PRZYKŁADÓW

Przykład 2

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : przekazywanie parametrów do f u n k c j i wątku i zwracanie wyników∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <pthread . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

typedef struct Arg { // s t r u k t u r a argumentów d l a wątku 1 .char napis [ 2 5 6 ] ;int rok ;int mies ;int dz ien ;

} Argument ;

void∗ watek1 ( void∗ arg ) {Argument∗ arg = ( Argument∗) a rg ;

p r i n t f ( ”Witaj %s w dniu %04d−%02d−%02d\n” ,arg−>napis ,arg−>rok ,arg−>mies ,arg−>dz ien

) ;

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/∗ wątek 2 . zwraca pewien dynamicznie tworzony napis ∗/void∗ watek2 ( void∗ l i c z b a ) {

char∗ napis ;int i ;p r i n t f ( ”Wątek 2 wywołany z argumentem liczbowym %d\n” , ( int ) l i c z b a ) ;

napi s = mal loc ( ( int ) l i c z b a + 1) ;i f ( napi s ) {

for ( i =0; i < ( int ) l i c z b a ; i++)napis [ i ] = ’ x ’ ;

nap i s [ ( int ) l i c z b a ] = 0 ;

61

6.2. WYKAZ PRZYKŁADÓW

}return napis ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t w1 , w2 ;Argument arg ;char∗ wynik ;

/∗ przygotowanie argumentów ∗/s t r cpy ( arg . napis , ”Wikibooks” ) ;arg . rok = 2010 ;arg . mies = 3 ;arg . dz ien = 14 ;

/∗ utworzenie dwóch wątków ∗/errno = pthr ead c r ea t e (&w1 , NULL, watek1 , &arg ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

e r rno = pthr ead c r ea t e (&w2 , NULL, watek2 , ( void ∗) 27) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

/∗ oczek iwanie na zakończen ie obu ∗/errno = p t h r e a d j o i n (w1 , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

e r rno = p t h r e a d j o i n (w2 , ( void ∗∗)&wynik ) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

i f ( wynik ) {p r i n t f ( ”wątek 2 zwróc i ł napi s : ’%s ’\n” , wynik ) ;f r e e ( wynik ) ;

}else

puts ( ”wątek 2 n i c n i e zwróc i ł ” ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

62

6.2. WYKAZ PRZYKŁADÓW

Przykład 4

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : a t r y b u t y wątku − wypisanie domyślnych w a r t o ś c i∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include < l i m i t s . h> // PTHREAD STACK MIN#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

void wyswiet l a t rybuty ( const p t h r e a d a t t r t ∗ a t t r ) {int x ;s i z e t rozmiar ;void∗ addr ;struct sched param param ;

puts ( ” atrybuty wątku” ) ;

// r o d z a j wątkup r i n t f ( ”∗ rodza j : ” ) ;e r rno = p t h r e a d a t t r g e t d e t a c h s t a t e ( at t r , &x ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t d e t a c h s t a t e ” ) ;

switch ( x ) {case PTHREAD CREATE JOINABLE:

puts ( ” j o i n a b l e ” ) ;break ;

case PTHREAD CREATE DETACHED:puts ( ” detached ” ) ;break ;

default :puts ( ” ??? ” ) ;

}

// adres i rozmiar s t o s uerrno = p t h r e a d a t t r g e t s t a c k a d d r ( att r , &addr ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t s t a c k a d d r ” ) ;p r i n t f ( ”∗ adres s to su : %p\n” , addr ) ;

e r rno = p t h r e a d a t t r g e t s t a c k s i z e ( at t r , &rozmiar ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t s t a c k s i z e ” ) ;

63

6.2. WYKAZ PRZYKŁADÓW

p r i n t f ( ”∗ rozmiar s to su : %d ( minimalny %d) \n” , rozmiar , PTHREAD STACK MIN) ;

// rozmiar obszaru z a b e z p i e c z a j ą c e g o s t o s uerrno = p t h r e a d a t t r g e t g u a r d s i z e ( att r , &rozmiar ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t g u a r d s i z e ” ) ;p r i n t f ( ”∗ rozmiar obszaru zabezp i e c za j ą c ego : %d\n” , rozmiar ) ;

// szeregowanieerrno = p t h r e a d a t t r g e t i n h e r i t s c h e d ( att r , &x ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t i n h e r i t s c h e d ” ) ;switch ( x ) {

case PTHREAD INHERIT SCHED:puts ( ”∗ parametry szeregowania d z i e d z i c z o n e ” ) ;break ;

case PTHREAD EXPLICIT SCHED:puts ( ”∗ parametry podawane bezpośredn io ” ) ;

//p r i n t f ( ” − algorytm szeregowania : ” ) ;e r rno = p t h r e a d a t t r g e t s c h e d p o l i c y ( att r , &x ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t s c h e d p o l i c y ” ) ;switch ( x ) {

case SCHED OTHER:puts ( ”SCHED OTHER” ) ;break ;

case SCHED RR:puts ( ”SCHED RR” ) ;break ;

case SCHED FIFO:puts ( ”SCHED FIFO” ) ;break ;

default :puts ( ” ??? ” ) ;

}

//errno = pthread att r get schedparam ( att r , &param ) ;t e s t e r r n o ( ” pthread att r get schedparam ” ) ;p r i n t f ( ” − p r i o r y t e t : %d\n” , param . s c h e d p r i o r i t y ) ;break ;

default :puts ( ” ??? ” ) ;

}

// z a k r e s szeregowaniaerrno = p t h r e a d a t t r g e t s c o p e ( att r , &x ) ;t e s t e r r n o ( ” p t h r e a d a t t r g e t s c o p e ” ) ;

p r i n t f ( ”∗ zakre s szeregowania : ” ) ;switch ( x ) {

case PTHREAD SCOPE PROCESS:

64

6.2. WYKAZ PRZYKŁADÓW

puts ( ” proces ” ) ;break ;

case PTHREAD SCOPE SYSTEM:puts ( ” system” ) ;break ;

default :puts ( ” ??? ” ) ;

}}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {p t h r e a d a t t r t a t t r ;

e r rno = p t h r e a d a t t r i n i t (& a t t r ) ;t e s t e r r n o ( ” p t h r e a d a t t r i n i t ” ) ;

wyswie t l a t rybuty (& a t t r ) ;return EXIT SUCCESS ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

65

6.2. WYKAZ PRZYKŁADÓW

Przykład 5

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : f u n k c j e f i n a l i z u j ą c e ( c leanup )∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>#include <uni s td . h> // s l e e p

#define t e s t e r r n o ( i n f o ) do { i f ( errno ) { per ro r ( i n f o ) ; e x i t (EXIT FAILURE);}} while (0 )

/∗ f u n k c j a f i n a l i z u j ą c a ∗/void zwo ln i j pamiec ( void∗ adres ) {

p r i n t f ( ” zwa ln ian i e pamięci spod adresu %p\n” , adres ) ;f r e e ( adres ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek ( void∗ id ) {char∗ t a b l i c a 1 = mal loc (100) ;char∗ t a b l i c a 2 = NULL;p r i n t f ( ”wątek #%d zaalokował 100 bajtów pod adresem %p\n” , ( int ) id ,

t a b l i c a 1 ) ;

pthread c leanup push ( zwoln i j pamiec , t a b l i c a 1 ) ;i f ( t a b l i c a 1 ) {

t a b l i c a 2 = mal loc (200) ;p r i n t f ( ”wątek #%d zaalokował 200 bajtów pod adresem %p\n” , ( int ) id ,

t a b l i c a 2 ) ;pthread c leanup push ( zwoln i j pamiec , t a b l i c a 2 ) ;

i f ( ( int ) id > 0)/∗ wątek s i ę kończy w tym punkcie , f u n k c j e f i n a l z u j ą c e

zos taną uruchomione ∗/p t h r e a d e x i t (NULL) ;

pthread c leanup pop (1) ;}

pthread c leanup pop (1) ;

p r i n t f ( ”wątek #%d zakończył s i ę \n” , ( int ) id ) ;return NULL;

}

66

6.2. WYKAZ PRZYKŁADÓW

//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t id1 ;pthread t id2 ;

/∗ utworzenie 2 wątków ∗/errno = pthr ead c r ea t e (&id1 , NULL, watek , ( void ∗) (0 ) ) ;t e s t e r r n o ( ” pth r ead c r ea t e (1 ) ” ) ;

e r rno = pthr ead c r ea t e (&id2 , NULL, watek , ( void ∗) (1 ) ) ;t e s t e r r n o ( ” pth r ead c r ea t e (2 ) ” ) ;

/∗ oczek iwanie na zakończen ie ∗/p t h r e a d j o i n ( id1 , NULL) ;p t h r e a d j o i n ( id2 , NULL) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

67

6.2. WYKAZ PRZYKŁADÓW

Przykład 6

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : f u n k c j e wykonywane j e d n o k r o t n i e∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

/∗ o b i e k t gwarantujący jednokro tne wykonanie , musi z o s t a ć za in ic jowany ∗/pthread once t program gotowy = PTHREAD ONCE INIT;

void i n i c j a l i z a c j a ( ) {/∗ i n i c j a l i z a c j a , np . p r e k a l k u l o w a n i e j a k i ś t a b l i c ,

o t w i e r a n i e p l i k u logowania i t p . ∗/puts ( ” Rozpoczynanie programu” ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek ( void∗ numer ) {pthread once(&program gotowy , i n i c j a l i z a c j a ) ;

p r i n t f ( ”Uruchomiono watek nr %d\n” , ( int ) numer ) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 10 /∗ l i c z b a wątków ∗/

int main ( ) {pthread t id [N ] ;int i ;

/∗ utworzenie wątków ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) i ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ oczek iwanie na j e g o zakończen ie ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

68

6.2. WYKAZ PRZYKŁADÓW

}

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

69

6.2. WYKAZ PRZYKŁADÓW

Przykład 7

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : przerywanie wątków − program tworzy 3 wątk i z różnymi∗ ustawieniami dotyczącymi przerywania :∗ 1) dopuszcza przerwanie asynchroniczne∗ 2) dopuszcza przerwanie opóźnione∗ 3) p r z e z pewien czas w o g ó l e b l o k u j e przerwania∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <pthread . h>#include <uni s td . h> // pause w watek3#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

void zakonczen ie ( void∗ numer ) {p r i n t f ( ” funkc ja f i n a l i z u j ą c a dla wątku #%d\n” , ( int ) numer ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek1 ( void∗ numer ) {int i , n ;

pthread c leanup push ( zakonczenie , numer ) ;

e r rno = p t h r e a d s e t c a n c e l s t a t e (PTHREAD CANCEL ENABLE, NULL) ;t e s t e r r n o ( ” p t h r e a d s e t c a n c e l s t a t e ” ) ;

e r rno = pth r ead s e t canc e l t ype (PTHREAD CANCEL ASYNCHRONOUS, NULL) ;t e s t e r r n o ( ” p th r ead s e t canc e l t ype ” ) ;

p r i n t f ( ”\ turuchomiono wątek #%d ( przerwanie asynchron iczne ) \n” , ( int )numer ) ;

while (1 ) {n = 1000000;for ( i =0; i < n ; i++)

/∗∗/ ;}

pthread c leanup pop (1) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

70

6.2. WYKAZ PRZYKŁADÓW

void∗ watek2 ( void∗ numer ) {int i , n ;pthread c leanup push ( zakonczenie , numer ) ;

e r rno = p t h r e a d s e t c a n c e l s t a t e (PTHREAD CANCEL ENABLE, NULL) ;t e s t e r r n o ( ” p t h r e a d s e t c a n c e l s t a t e ” ) ;

e r rno = pth r ead s e t canc e l t ype (PTHREAD CANCEL DEFERRED, NULL) ;t e s t e r r n o ( ” p th r ead s e t canc e l t ype ” ) ;

p r i n t f ( ”\ turuchomiono wątek #%d ( przerwanie opóźnione ) \n” , ( int ) numer ) ;while (1 ) {

p t h r e a d t e s t c a n c e l ( ) ; // punkt przerwanian = 1000000;for ( i =0; i < n ; i++)

/∗∗/ ;}

pthread c leanup pop (1) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek3 ( void∗ numer ) {pthread c leanup push ( zakonczenie , numer ) ;e r rno = p t h r e a d s e t c a n c e l s t a t e (PTHREAD CANCEL DISABLE, NULL) ;t e s t e r r n o ( ” p t h r e a d s e t c a n c e l s t a t e ” ) ;

p r i n t f ( ”\ turuchomiono wątek #%d ( przez 2 sekundy n i e można przerwać ) \n” ,( int ) numer ) ;

s l e e p (2 ) ;

p r i n t f ( ”\ twątek #%d można już przerwać \n” , ( int ) numer ) ;e r rno = p t h r e a d s e t c a n c e l s t a t e (PTHREAD CANCEL ENABLE, NULL) ;t e s t e r r n o ( ” p t h r e a d s e t c a n c e l s t a t e ” ) ;pause ( ) ;

pthread c leanup pop (1) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void przerwanie ( pthread t id , const char∗ napis ) {p r i n t f ( ”%s : wysyłanie sygnału przerwania do wątku\n” , napi s ) ;e r rno = pthread cance l ( id ) ;t e s t e r r n o ( ” pthread cance l ” ) ;

p r i n t f ( ”%s : wysłano , oczek iwanie na zakończen ie \n” , napi s ) ;e r rno = p t h r e a d j o i n ( id , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

p r i n t f ( ”%s : wątek zakończony\n” , napi s ) ;

71

6.2. WYKAZ PRZYKŁADÓW

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t id [ 3 ] ;

/∗ utworzenie wątków ∗/errno = pthr ead c r ea t e (& id [ 0 ] , NULL, watek1 , ( void ∗) (0 ) ) ;t e s t e r r n o ( ” pth r ead c r ea t e (1 ) ” ) ;

e r rno = pthr ead c r ea t e (& id [ 1 ] , NULL, watek2 , ( void ∗) (1 ) ) ;t e s t e r r n o ( ” pth r ead c r ea t e (2 ) ” ) ;

e r rno = pthr ead c r ea t e (& id [ 2 ] , NULL, watek3 , ( void ∗) (2 ) ) ;t e s t e r r n o ( ” pth r ead c r ea t e (3 ) ” ) ;

/∗ przerywanie k o l e j n y c h wątków ∗/przerwanie ( id [ 0 ] , ”#0” ) ;przerwanie ( id [ 1 ] , ”#1” ) ;przerwanie ( id [ 2 ] , ”#2” ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

72

6.2. WYKAZ PRZYKŁADÓW

Przykład 8

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : różne zachowanie mutexów w pthreads przy p r ó b i e ponownego∗ z a ł o ż e n i a b lokady∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <errno . h>

#define USE UNIX98#include <pthread . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

pthread t id ;pthread mutex t mutex ;pthread mutexatt r t mutexattr ;

void∗ watek ( void∗ arg ) {int errno ;

// 1puts ( ” przed wykonaniem pthread mutex lock (1 ) ” ) ;

e r rno = pthread mutex lock(&mutex ) ;t e s t e r r n o ( ” pthread mutex lock (1 ) ” ) ;

puts ( ” . . . wykonano pthread mutex lock (1 ) ” ) ;

// 2puts ( ” przed wykonaniem pthread mutex lock (2 ) ” ) ;

e r rno = pthread mutex lock(&mutex ) ;t e s t e r r n o ( ” pthread mutex lock (2 ) ” ) ;

puts ( ” . . . wykonano pthread mutex lock (2 ) ” ) ;

// 3puts ( ” przed wykonaniem pthread mutex unlock (2 ) ” ) ;

e r rno = pthread mutex unlock(&mutex ) ;t e s t e r r n o ( ” pthread mutex unlock (2 ) ” ) ;

puts ( ” . . . wykonano pthread mutex unlock (2 ) ” ) ;

// 4puts ( ” przed wykonaniem pthread mutex unlock (1 ) ” ) ;

e r rno = pthread mutex unlock(&mutex ) ;t e s t e r r n o ( ” pthread mutex unlock (1 ) ” ) ;

puts ( ” . . . wykonano pthread mutex unlock (1 ) ” ) ;

73

6.2. WYKAZ PRZYKŁADÓW

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( int argc , char∗ argv [ ] ) {int errno ;

p th r ead mutexa t t r i n i t (&mutexattr ) ;

i f ( argc > 1) {switch ( a t o i ( argv [ 1 ] ) ) {

case 1 :puts ( ”mutex typu PTHREAD MUTEX ERRORCHECK” ) ;pthread mutexat t r s e t type (&mutexattr , PTHREAD MUTEX ERRORCHECK) ;break ;

case 2 :puts ( ”mutex typu PTHREAD MUTEX RECURSIVE” ) ;pthread mutexat t r s e t type (&mutexattr , PTHREAD MUTEX RECURSIVE) ;break ;

default :puts ( ”mutex typu PTHREAD MUTEX NORMAL” ) ;pthread mutexat t r s e t type (&mutexattr , PTHREAD MUTEX NORMAL) ;break ;

}}else {

puts ( ” użyc i e : program [ 0 | 1 | 2 ] ” ) ;return EXIT FAILURE ;

}

/∗ i n i c j a l i z a c j a mutexu ∗/errno = pthread mutex in i t (&mutex , &mutexattr ) ;t e s t e r r n o ( ” pthread mutex in i t ” ) ;

/∗ utworzenie wstku ∗/errno = pthr ead c r ea t e (&id , NULL, watek , NULL) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

/∗ oczek iwanie na j e g o zakończen ie ∗/p t h r e a d j o i n ( id , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

puts ( ”program zakończony ” ) ;return EXIT SUCCESS ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

74

6.2. WYKAZ PRZYKŁADÓW

Przykład 9

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : zmienne warunkowe∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <pthread . h>#include <errno . h>#include <uni s td . h> // s l e e p

pthread mutex t mutex = PTHREAD MUTEX INITIALIZER;pthread cond t cond = PTHREAD COND INITIALIZER;

char warunek = 0 ;

void∗ watek ( void∗ numer ) {p r i n t f ( ”\ turuchomiono wątek #%d\n” , ( int ) numer ) ;while (1 ) {

pthread mutex lock(&mutex ) ;do {

i f ( warunek )break ;

else {p r i n t f ( ”\ twątek #%d oczeku je na sygnał . . . \ n” , ( int ) numer ) ;pthread cond wait (&cond , &mutex ) ;p r i n t f ( ”\ t . . . wątek #%d otrzymał sygnał !\n” , ( int ) numer ) ;

}} while (1 ) ;pthread mutex unlock(&mutex ) ;/∗ . . . ∗/

}

return NULL;}

#define N 5 /∗ l i c z b a wątków ∗/

int main ( ) {pthread t id [N ] ;int i ;

puts ( ” początek programu” ) ;

/∗ utworzenie wątków ∗/for ( i =0; i < N; i++) {

75

6.2. WYKAZ PRZYKŁADÓW

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) ( i +1) ) ;i f ( errno ) {

per ro r ( ” p th r ead c r ea t e ” ) ;return EXIT FAILURE ;

}}

/∗ wysyłanie sygnałów ∗/

s l e e p (1 ) ;puts ( ” p th r ead cond s i gna l − s y g n a l i z a c j a ” ) ;p th r ead cond s i gna l (&cond ) ;

s l e e p (1 ) ;puts ( ” pthread cond broadcast − r o z g ł a s z a n i e ” ) ;pthread cond broadcast (&cond ) ;

s l e e p (1 ) ;

/∗ kończymy proces , bez og lądan ia s i ę na wątk i ∗/puts ( ” kon iec programu” ) ;return EXIT SUCCESS ;

}

76

6.2. WYKAZ PRZYKŁADÓW

Przykład 10

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : prywatne dane wątków∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>#include <uni s td . h>#include <s t r i n g . h>

#define t e s t e r r n o ( i n f o ) do { i f ( errno ) { per ro r ( i n f o ) ; e x i t (EXIT FAILURE);}} while (0 )

pthread key t k lucz ;

/∗ f u n k c j a wypsuje wiersz , p o p r z e d z ą j ą c go pre f i k sem przypisanym do wątku∗/

void wyswiet l ( const char∗ napis ) {char∗ p r e f i k s = (char∗) p t h r e a d g e t s p e c i f i c ( k lucz ) ;i f ( p r e f i k s == NULL)

/∗ n a l e ż y z a b e z p i e c z y ć s i ę przed sy tuac ją , gdy wywołującywątek nie przyporządkował nic do k l u c z a ∗/

puts ( napi s ) ;else

p r i n t f ( ”%s : %s \n” , p r e f i k s , nap i s ) ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/∗ d e s t r u k t o r k l u c z a ∗/void des t rukto r ( void∗ napis ) {

p r i n t f ( ”wywołano dest ruktor , adres pamięci do zwo ln i en ia : %p ( ’% s ’ ) \n” ,napis ,(char∗) napi s

) ;f r e e ( napis ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek ( void∗ napis ) {/∗ u s t a w i e n i e p r e f i k s u w l o k a l n y c h danych wątku ∗/int s t a t u s = p t h r e a d s e t s p e c i f i c ( klucz , napi s ) ;

77

6.2. WYKAZ PRZYKŁADÓW

i f ( s t a t u s )f p r i n t f ( s tde r r , ” p t h r e a d s e t s p e c i f i c : %s \n” , s t r e r r o r ( s t a t u s ) ) ;

elsep r i n t f ( ” adres napisu : %p ( ’% s ’ ) \n” , napis , (char∗) napi s ) ;

wyswiet l ( ”Witaj w równoległym ś w i e c i e ! ” ) ;s l e e p (1 ) ;wyswiet l ( ”Wątek wykonuje pracę ” ) ;s l e e p (1 ) ;wyswiet l ( ”Wątek zakończony ” ) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

char∗ strdup ( const char∗) ;

#define N 3

int main ( ) {pthread t id [N ] ;int i ;char∗ p r e f i k s [ 3 ] = {”∗∗∗” , ” ! ! ! ” , ”###” } ; // p r e f i k s y d l a komunikatów z

wątków

/∗ utworzenie k l u c z a ∗/errno = pthr ead key c r ea t e (&klucz , de s t rukto r ) ;t e s t e r r n o ( ” pth r ead key c r ea t e ” ) ;

/∗ utworzenie wątków ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) strdup ( p r e f i k s [ i %3 ] ) ) ;

t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;}

/∗ oczek iwanie na i c h zakończen ie ∗/for ( i =0; i < N; i++)

p t h r e a d j o i n ( id [ i ] , NULL) ;

/∗ u s u n i ę c i e k l u c z a ∗/errno = p th r e ad k ey d e l e t e ( k lucz ) ;t e s t e r r n o ( ” p t h r ea d k ey d e l e t e ” ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

char∗ strdup ( const char∗ s ) {char ∗d = NULL;i f ( s ) {

78

6.2. WYKAZ PRZYKŁADÓW

d = (char∗) mal loc ( s t r l e n ( s ) +1) ;i f (d)

s t r cpy (d , s ) ;}return d ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

79

6.2. WYKAZ PRZYKŁADÓW

Przykład 11

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : b a r i e r y∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L

#include <pthread . h>#include <s t d i o . h>#include <s t d l i b . h>#include <s t r i n g . h>#include <errno . h>#include <uni s td . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

p t h r e a d b a r r i e r t b a r i e r a ;

void∗ watek ( void∗ numer ) {int s , s t a t u s ;

s = rand ( ) % 4 + 1 ; // oczek iwanie 1−4 sp r i n t f ( ”\ twątek #%d rozpoczęty , z o s t a n i e wstrzymany na %d sekund\n” , ( int

)numer , s ) ;

s l e e p ( s ) ;

p r i n t f ( ”\ twątek #%d os i ągną ł b a r i e r ę \n” , ( int ) numer ) ;s t a t u s = p t h r e a d b a r r i e r w a i t (& b a r i e r a ) ;switch ( s t a t u s ) {

case 0 : // okbreak ;

case PTHREAD BARRIER SERIAL THREAD:p r i n t f (

”\ twszy s tk i e wątki o s i ągnę ły b a r i e r ę ”” (PTHREAD BARRIER SERIAL THREAD w wąteku #%d) \n” ,( int ) numer

) ;break ;

default :f p r i n t f ( s tde r r , ” p t h r e a d b a r r i e r w a i t : %s \n” , s t r e r r o r ( s t a t u s ) ) ;break ;

}return NULL;

80

6.2. WYKAZ PRZYKŁADÓW

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 10 /∗ l i c z b a wątków ∗/

int main ( ) {int i ;p thread t id [N ] ;

srand ( time (NULL) ) ;

p r i n t f ( ” z o s t a n i e uruchomionych %d wątków\n” , N) ;

/∗ i n i c j a l i z a c j a b a r i e r y − N wątków ∗/errno = p t h r e a d b a r r i e r i n i t (&bar i e ra , NULL, N) ;t e s t e r r n o ( ” p t h r e a d b a r r i e r i n i t ” ) ;

/∗ utworzenie N wątków ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) i ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ o c z e k i w a i e na d o j ś c i e do b a r i e r y w s z y s t k i c h wątków ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

}

/∗ z w o l n i e n i e b a r i e r y ∗/errno = p t h r e a d b a r r i e r d e s t r o y (& b a r i e r a ) ;t e s t e r r n o ( ” p t h r e a d b a r r i e r d e s t r o y ” ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

81

6.2. WYKAZ PRZYKŁADÓW

Przykład 12

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : zmiana rozmiaru s t o s u wątku∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L

#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include < l i m i t s . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

#define N (100∗1024)

/∗ wątek używa s p o r e j t a b l i c y a lokowanej na s t o s i e ∗/void∗ watek ( void∗ arg ) {

char t a b l i c a [N ] ;int i ;for ( i =0; i < N; i++)

t a b l i c a [ i ] = 0 ;

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( int argc , char∗ argv [ ] ) {pthread t id ;p t h r e a d a t t r t a t t r ;s i z e t rozmiar ;

e r rno = p t h r e a d a t t r i n i t (& a t t r ) ;i f ( er rno ) {

per ro r ( ” p t h r e a d a t t r i n i t ” ) ;return EXIT FAILURE ;

}

i f ( argc > 1) {rozmiar = a t o i ( argv [ 1 ] ) ;p r i n t f ( ” rozmiar s to su usta lony przez użytkownika : %u\n” , rozmiar ) ;p r i n t f ( ”minimalny rozmiar s to su : %u\n” , PTHREAD STACK MIN) ;

er rno = p t h r e a d a t t r s e t s t a c k s i z e (&attr , rozmiar ) ;t e s t e r r n o ( ” p t h r e a d a t t r s e t s t a c k s i z e ” ) ;

82

6.2. WYKAZ PRZYKŁADÓW

}else {

p t h r e a d a t t r g e t s t a c k s i z e (&attr , &rozmiar ) ;p r i n t f ( ”domyślny rozmiar s to su : %u\n” , rozmiar ) ;

}

errno = pthr ead c r ea t e (&id , &attr , watek , NULL) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

p t h r e a d j o i n ( id , NULL) ;puts ( ”wątek zakończony ” ) ;

p t h r e a d a t t r d e s t r o y (& a t t r ) ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

83

6.2. WYKAZ PRZYKŁADÓW

Przykład 13

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : wysy łanie sygnałow UNIX−owych do wątków∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L#include <s t d l i b . h>#include <s t d i o . h>#include <errno . h>#include <pthread . h>#include <s i g n a l . h>#include <uni s td . h> // s l e e p

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

pthread t main id ; // id głównego wątek

// f u n k c j a wątkuvoid∗ watek ( void∗ nieuzywany ) {

puts ( ”\ twątek s i ę rozpoczą ł ” ) ;s l e e p (1 ) ;

puts ( ”\ twątek wysyła sygnał SIGUSR1 do głównego wątku” ) ;e r rno = p t h r e a d k i l l ( main id , SIGUSR1) ;t e s t e r r n o ( ” p t h r e a d k i l l ” ) ;

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t id ;int signum ;s i g s e t t mask ;

// b lokowanie SIGUSR1s igemptyset (&mask) ;s i g a dd s e t (&mask , SIGUSR1) ;

errno = pthread s igmask (SIG BLOCK, &mask , NULL) ;t e s t e r r n o ( ” p t h r e a d k i l l ” ) ;

// odc zy t id głównego wątkumain id = p t h r e a d s e l f ( ) ;

84

6.2. WYKAZ PRZYKŁADÓW

// utworzen ie wątkuerrno = pthr ead c r ea t e (&id , NULL, watek , NULL) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

// oczek iwanie na sygnałputs ( ”wątek główny oczeku je na sygnał ” ) ;

s i g w a i t (&mask , &signum ) ;t e s t e r r n o ( ” s i g w a i t ” ) ;i f ( signum == SIGUSR1)

puts ( ”wątek główny otrzymał sygnał SIGUSR1” ) ;else

p r i n t f ( ”wątek główny otrzymał sygnał %d\n” , signum ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

85

6.2. WYKAZ PRZYKŁADÓW

Przykład 14

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : odc zy t czasu CPU, j a k i z u ż y ł wątek∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L

#include <s t d l i b . h>#include <s t d i o . h>#include <errno . h>

#include <pthread . h>#include <uni s td . h>#include <time . h> // s l e e p#include <s t r i n g . h> // s t r e r r o r

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

// f u n k c j a zwraca czas w mi l i sekundach d l a wskazanego zegaralong c lock ms ( const c l o c k i d t i d z e g a r a ) ;

// f u n k c j a zwraca czas CPU d l a wątku (w mi l i sekundach )long ge t th r ead t ime ( pthread t id ) ;

/∗ parametry wątku ∗/typedef struct {

int id ; // numerint n ; // l i c z b a i t e r a c j i

} parametry ;

// f u n k c j a wątkuvoid∗ watek ( void∗ arg ) {

parametry∗ arg = ( parametry ∗) a rg ;int i ;p r i n t f ( ”wątek #%d uruchomiony , dwa razy wykona %d pustych p ę t l i \n” ,

( int ) arg−>id ,( int ) arg−>n

) ;

for ( i =0; i < arg−>n ; i++)/∗ z u ż y c i e czasu procesora ∗/ ;

s l e e p (2 ) ;

for ( i =0; i < arg−>n ; i++)/∗ z u ż y c i e czasu procesora ∗/ ;

86

6.2. WYKAZ PRZYKŁADÓW

/∗ podsumowanie pracy ∗/p r i n t f ( ”wątek #%d zakończony , zużył %ldms czasu proce sora \n” ,

( int ) arg−>id ,c lock ms (CLOCK THREAD CPUTIME ID)

) ;return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 10 // l i c z b a wątków

int main ( ) {pthread t id [N ] ;parametry param [N ] ;int i ;

srand ( time (NULL) ) ;

p r i n t f ( ” początek programu , uruchomianie z o s t a n i e %d wątków\n” , N) ;

/∗ utworzenie wątku ∗/for ( i =0; i < N; i++) {

param [ i ] . id = i ;param [ i ] . n = rand ( ) % 100000000 + 1 ;

errno = pthread c r ea t e (& id [ i ] , NULL, watek , &param [ i ] ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ s tan na mniej w i ę c e j półmetku ∗/s l e e p (1 ) ;puts ( ”po około sekundz ie wątki zużyły : ” ) ;for ( i =0; i < N; i++)

p r i n t f ( ”∗ #%d : %ldms\n” , i , g e t th r ead t ime ( id [ i ] ) ) ;

/∗ oczek iwanie na zakończen ie wątków ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

}

/∗ j e s z c z e podsumowanie ∗/puts ( ”” ) ;p r i n t f ( ”główny wątek zużył %ldms czasu proce sora \n” , c lock ms (

CLOCK THREAD CPUTIME ID) ) ;p r i n t f ( ” proces zużył %ldms czasu proce sora \n” , c lock ms (

CLOCK PROCESS CPUTIME ID) ) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

long ge t th r ead t ime ( pthread t id ) {

87

6.2. WYKAZ PRZYKŁADÓW

c l o c k i d t i d z e g a r a ;

er rno = pthread ge t cpuc l o ck id ( id , &i d z e g a r a ) ;t e s t e r r n o ( ” pthread ge t cpuc l o ck id ” ) ;

return c lock ms ( i d z e g a r a ) ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

long c lock ms ( const c l o c k i d t i d z e g a r a ) {struct t imespec czas ;i f ( c l o c k g e t t i m e ( id zegara , &czas ) ) {

per ro r ( ” c l o c k g e t t i m e ” ) ;e x i t (EXIT FAILURE) ;

}else

return ( czas . t v s e c ∗ 1000) +( czas . t v n s e c /1000000) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

88

6.2. WYKAZ PRZYKŁADÓW

Przykład 15

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : s e k c j a kr y tyc zna z użyciem mutexów∗ j e ś l i zde f in iowane z o s t a n i e BLOKADA, mutex b l o k u j e∗ dos tęp do zmiennej , w przeciwnym r a z i e wątk i zmienia ją∗ j ą bez żadne j s y n c h r o n i z a c j i , co może prowadzić do błędu∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

#define N 10 /∗ l i c z b a wątków ∗/#define K 1000 /∗ l i c z b a i t e r a c j i ( z tą war toś c ią n a l e ż y eksperymentować )

∗/

pthread mutex t blokada ;int l i c z n i k = 0 ; // g l o b a l n y l i c z n i k , powinien być chroniony b lokadą

void ms s leep (unsigned ms) {struct t imespec req ;req . t v s e c = (ms / 1000) ;req . tv n s e c = (ms % 1000 ∗ 1000000) ;nanos leep(&req , NULL) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void∗ watek ( void∗ numer ) {int i ;for ( i =0; i < K; i++) {

#ifde f BLOKADAerrno = pthread mutex lock(&blokada ) ;t e s t e r r n o ( ” pthread mutex lock ” ) ;

#endifl i c z n i k = l i c z n i k + 1 ;ms s l eep (1 ) ;

#ifde f BLOKADAerrno = pthread mutex unlock(&blokada ) ;t e s t e r r n o ( ” pthread mutex unlock ” ) ;

#endif}

89

6.2. WYKAZ PRZYKŁADÓW

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {pthread t id [N ] ;int i ;

p r i n t f ( ” l i c z n i k = %d\n” , l i c z n i k ) ;

e r rno = pthread mutex in i t (&blokada , NULL) ;t e s t e r r n o ( ” pthread mutex in i t ” ) ;

/∗ utworzenie wątku ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) i ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ oczek iwanie na j e g o zakończen ie ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

}

p r i n t f ( ” l i c z n i k = %d , spodziewana wartość = %d %s \n” ,l i c z n i k ,N∗K,( l i c z n i k != N∗K ? ”BŁĄD ! ! ! ” : ”” )

) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

90

6.2. WYKAZ PRZYKŁADÓW

Przykład 16

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : b lokady z a p i s / odczy ( rwlock )∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define POSIX C SOURCE 200809L#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <errno . h>#include <time . h>

void ms s leep ( const unsigned ms) ;#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}

while (0 )

pthread rw lock t blokada ;int wartosc ; // o b i e k t chroniony b lokadą

/∗ wątek zmienia wartość ∗/void∗ p i s a r z ( void∗ numer ) {

while (1 ) {p r i n t f ( ” p i s a r z #%d czeka na dostęp \n” , ( int ) numer ) ;e r rno = pthread rwlock wr lock (&blokada ) ;t e s t e r r n o ( ” pthread rwlock wr lock ” ) ;p r i n t f ( ” p i s a r z #%d ustawia nową wartość \n” , ( int ) numer ) ;

ms s l eep (113) ;

p r i n t f ( ” p i s a r z #%d zwalnia blokadę \n” , ( int ) numer ) ;e r rno = pthread rwlock un lock (&blokada ) ;t e s t e r r n o ( ” pthread rwlock un lock ” ) ;

ms s l eep (317) ;

}

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/∗ wątek t y l k o o d c z y t u j e wartość ∗/void∗ c z y t e l n i k ( void∗ numer ) {

int errno ;while (1 ) {

p r i n t f ( ” c z y t e l n i k #%d czeka na dostęp \n” , ( int ) numer ) ;

91

6.2. WYKAZ PRZYKŁADÓW

errno = pthread rw lock rd lock (&blokada ) ;t e s t e r r n o ( ” pthread rw lock rd lock ” ) ;p r i n t f ( ” c z y t e l n i k #%d odczytu je wartość \n” , ( int ) numer ) ;

ms s l eep (13) ;

p r i n t f ( ” c z y t e l n i k #%d zwalnia blokadę \n” , ( int ) numer ) ;e r rno = pthread rwlock un lock (&blokada ) ;t e s t e r r n o ( ” pthread rwlock un lock ” ) ;

ms s l eep (13) ;

}return NULL;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 5 /∗ l i c z b a wątków ∗/#define K 2

int main ( ) {pthread t id ;int i ;

p t h r e a d r w l o c k i n i t (&blokada , NULL) ;

/∗ utworzenie K wątków p i s z ą c y c h ∗/for ( i =0; i < K; i++) {

errno = pthread c r ea t e (&id , NULL, p i sa rz , ( void ∗) i ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ utworzenie N wątków c z y t a j ą c y c h ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (&id , NULL, c zy t e ln i k , ( void ∗) i ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}

/∗ k i l k a sekund na pracę wątków i koniec ∗/ms s leep (1500) ;

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

void ms s leep ( const unsigned ms) {struct t imespec req ;req . t v s e c = (ms / 1000) ;req . tv n s e c = (ms % 1000 ∗ 1000000) ;nanos leep(&req , NULL) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

92

6.2. WYKAZ PRZYKŁADÓW

Przykład 17

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : s y n c h r o n i z a c j a między wątkami różnych procesów∗ w s p ó ł d z i e l o n y mutex i zmienna warunkowa∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define XOPEN SOURCE#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <pthread . h>#include <sys /shm . h>

#include <errno . h>#include <uni s td . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

struct pamiec dz i e l ona {/∗ w s p ó ł d z i e l o n e mutex i zmienna warunkowa ∗/pthread mutex t mutex ;pthread cond t cond ;pthread mutexatt r t mattr ;p th r ead condat t r t c a t t r ;

/∗ dane ∗/char napi s dostepny ;char napis [ 2 5 6 ] ;

} ∗pamiec ;

/∗ proces 1 tworzy segment pamięci wspólnej , tworzy mutex i zmiennąwarunkową WSPÓŁDZIELONEz innymi procesami , po czym o c z e k u j e na sygnał , aż napis s t a n i e s i ę

dostępny ∗/void proces1 ( ) {

int shmid ;int errno ;

shmid = shmget (IPC PRIVATE, s izeof ( pamiec ) , 0666) ;t e s t e r r n o ( ”shm open” ) ;p r i n t f ( ” id segmentu pamięci d z i e l o n e j : %d\n” , shmid ) ;

pamiec = shmat ( shmid , 0 , 0) ;t e s t e r r n o ( ”shmat” ) ;p r i n t f ( ” adres przyłączonego segmentu : %p\n” , ( void ∗) pamiec ) ;

93

6.2. WYKAZ PRZYKŁADÓW

/∗ i n i c j a l i z a c j a ∗/pamiec−>napi s dostepny = 0 ;memset ( pamiec−>napis , 0 , s izeof ( pamiec−>napis ) ) ;

/∗ tw orz en ie mutexu i zmiennej warunkowej ∗/errno = pth r ead mutexa t t r i n i t (&pamiec−>mattr ) ;t e s t e r r n o ( ” p th r ead mutexa t t r i n i t ” ) ;

e r rno = pthread mutexat t r se tpshared (&pamiec−>mattr ,PTHREAD PROCESS SHARED) ;

t e s t e r r n o ( ” pthread mutexat t r se tpshared ” ) ;

e r rno = pthread mutex in i t (&pamiec−>mutex , &pamiec−>mattr ) ;t e s t e r r n o ( ” pthread mutex in i t ” ) ;

/∗ tw orz en ie mutexu i zmiennej warunkowej ∗/errno = p t h r e a d c o n d a t t r i n i t (&pamiec−>c a t t r ) ;t e s t e r r n o ( ” p t h r e a d c o n d a t t r i n i t ” ) ;

e r rno = pthread condat t r s e tp sha red (&pamiec−>cat t r ,PTHREAD PROCESS SHARED) ;

t e s t e r r n o ( ” pthread condat t r s e tp sha red ” ) ;

e r rno = p t h r e a d c o n d i n i t (&pamiec−>cond , &pamiec−>c a t t r ) ;t e s t e r r n o ( ” p t h r e a d c o n d i n i t ” ) ;

/∗ oczek iwanie na u s t a w i e n i e napisu p r z e z inny proces ∗/errno = pthread mutex lock(&pamiec−>mutex ) ;t e s t e r r n o ( ” pthread mutex lock ” ) ;do {

i f ( pamiec−>napi s dostepny ) {p r i n t f ( ” inny proces us tawi ł napi s : ’%s ’\n” , pamiec−>napis ) ;break ;

}else {

puts ( ” pthread cond wait ” ) ;e r rno = pthread cond wait (&pamiec−>cond , &pamiec−>mutex ) ;t e s t e r r n o ( ” pthread cond wait ” ) ;

}} while (1 ) ;

e r rno = pthread mutex unlock(&pamiec−>mutex ) ;t e s t e r r n o ( ” pthread mutex unlock ” ) ;

/∗ o d ł ą c z e n i e od segmentu pamięci ∗/shmdt ( pamiec ) ;t e s t e r r n o ( ”shmdt” ) ;

/∗ i skasowanie go ∗/shmctl ( shmid , IPC RMID , NULL) ;

return ;}

94

6.2. WYKAZ PRZYKŁADÓW

//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

/∗ proces 2 p r z y ł ą c z a s i ę do segmentu i używając w s p ó ł d z i e l o n e g o mutexu izmiennejwarunkowej ustawia napis i s y g n a l i z u j e go procesowi 1 f u n k c j ą

p t h r e a d c o n d s i g n a l ∗/void proces2 ( int shmid , const char∗ napis ) {

int errno ;

pamiec = shmat ( shmid , 0 , 0) ;t e s t e r r n o ( ”shmat” ) ;p r i n t f ( ” adres przyłączonego segmentu : %p\n” , ( void ∗) pamiec ) ;

e r rno = pthread mutex lock(&pamiec−>mutex ) ;t e s t e r r n o ( ” pthread mutex lock ” ) ;

s t r c a t ( pamiec−>napis , nap i s ) ; // uwaga : możliwe p r z e p e ł n i e n i e bu forapamiec−>napi s dostepny = 1 ;

errno = pthr ead cond s i gna l (&pamiec−>cond ) ;t e s t e r r n o ( ” p th r ead cond s i gna l ” ) ;

e r rno = pthread mutex unlock(&pamiec−>mutex ) ;t e s t e r r n o ( ” pthread mutex unlock ” ) ;

p r i n t f ( ” proces us tawi ł napi s ’%s ’ i wykonał p th r ead cond s i gna l \n” , napi s) ;

shmdt ( pamiec ) ;t e s t e r r n o ( ”shmdt” ) ;

}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( int argc , char∗ argv [ ] ) {i f ( argc > 2) {

p r i n t f ( ” proces 2 : segment pamięci d z i e l o n e j %d\n” , a t o i ( argv [ 1 ] ) ) ;proces2 ( a t o i ( argv [ 1 ] ) , argv [ 2 ] ) ;

}else {

puts ( ” proces 1” ) ;proces1 ( ) ;

}

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

95

6.2. WYKAZ PRZYKŁADÓW

Przykład 18

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : p t h r e a d a t f o r k∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define XOPEN SOURCE 700#include <s t d l i b . h>#include <s t d i o . h>#include <s t r i n g . h>#include <pthread . h>#include <errno . h>#include <uni s td . h> // s l e e p#include <sys / wait . h> // w a i t p i d

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

void∗ watek ( void∗ numer ) {p r i n t f ( ”\ turuchomiono wątek #%d\n” , ( int ) numer ) ;while (1 ) {

p r i n t f ( ”\ t \ twątek #%d w p r o c e s i e #%d\n” , ( int )numer , ge tp id ( ) ) ;u s l e ep (700∗1000) ;

}

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 3 /∗ l i c z b a wątków ∗/

pthread t id [N ] ;

void i n i c j a l i z a c j a w a t k o w ( ) {int i ;p r i n t f ( ” tworzen ie %d wątków w p r o c e s i e %d\n” , N, getp id ( ) ) ;

/∗ utworzenie wątków ∗/for ( i =0; i < N; i++) {

errno = pthread c r ea t e (& id [ i ] , NULL, watek , ( void ∗) ( i +1) ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

}}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

int main ( ) {p i d t pid ;

96

6.2. WYKAZ PRZYKŁADÓW

puts ( ” początek programu” ) ;i n i c j a l i z a c j a w a t k o w ( ) ;

/∗ r e j e s t r o w a n i e f u n k c j i wykonywanej w p r o c e s i e potomnym ∗/errno = pthr ead a t f o rk (NULL, NULL, i n i c j a l i z a c j a w a t k o w ) ;t e s t e r r n o ( ” pth r ead a t f o rk ” ) ;

s l e e p (1 ) ;

pid = fo rk ( ) ;p r i n t f ( ” f o rk => %d\n” , pid ) ;switch ( pid ) {

case −1:t e s t e r r n o ( ” f o rk ” ) ;break ;

case 0 : // proces potomnys l e e p (2 ) ;break ;

default : // proces nadrzędnywaitp id ( pid , NULL, 0) ;t e s t e r r n o ( ” waitp id ” ) ;break ;

}

/∗ kończymy proces , bez og lądan ia s i ę na wątk i ∗/return EXIT SUCCESS ;

}

97

6.2. WYKAZ PRZYKŁADÓW

Przykład 19

/∗∗ Przykładowy program d l a kursu ”POSIX Threads” z w i k i b o o k s . p l∗∗ Temat : p r i o r y t e t y wątków∗∗ Autor : Wojciech Muła∗ Ostatn ia zmiana : 2010−03−xx∗/

#define XOPEN SOURCE 500#include <s t d l i b . h>#include <s t d i o . h>#include <pthread . h>#include <sched . h>#include <errno . h>#include <uni s td . h>

#define t e s t e r r n o (msg) do{ i f ( errno ) { per ro r (msg) ; e x i t (EXIT FAILURE) ;}}while (0 )

typedef struct {int l i c z n i k ;char p r z e r w i j ;int p r i o r y t e t ;

} Arg ;

/∗ f u n k c j a wykonywana w wątku − z w i ę k s z a l i c z n i k ∗/void∗ watek ( void∗ arg ) {

Arg ∗ arg = ( Arg∗) a rg ;

arg−> l i c z n i k = 0 ;while ( ! arg−>p r z e r w i j ) {

arg−> l i c z n i k += 1 ;us l e ep (10) ;

}

return NULL;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#define N 4 /∗ l i c z b a wątków ∗/

int main ( int argc , char∗ argv [ ] ) {pthread t id [N ] ;p t h r e a d a t t r t a t t r ;Arg arg [N ] ;int pmin , pmax ;int i , s c h e d p o l i c y ;struct sched param sp ;

s c h e d p o l i c y = SCHED OTHER;

98

6.2. WYKAZ PRZYKŁADÓW

i f ( argc > 1)switch ( a t o i ( argv [ 1 ] ) ) {

case 0 :s c h e d p o l i c y = SCHED OTHER;break ;

case 1 :s c h e d p o l i c y = SCHED RR;break ;

case 2 :s c h e d p o l i c y = SCHED FIFO;break ;

}else {

puts ( ”program [ 0 | 1 | 2 ] ” ) ;return EXIT FAILURE ;

}

pmin = s c h e d g e t p r i o r i t y m i n ( s c h e d p o l i c y ) ;pmax = s c h e d g e t p r i o r i t y m a x ( s c h e d p o l i c y ) ;switch ( s c h e d p o l i c y ) {

case SCHED OTHER:p r i n t f ( ”SCHED OTHER: p r i o r y t e t y w z a k r e s i e %d . . . %d\n” , pmin , pmax) ;break ;

case SCHED RR:p r i n t f ( ”SCHED RR: p r i o r y t e t y w z a k r e s i e %d . . . %d\n” , pmin , pmax) ;break ;

case SCHED FIFO:p r i n t f ( ”SCHED FIFO: p r i o r y t e t y w z a k r e s i e %d . . . %d\n” , pmin , pmax) ;break ;

}

errno = p t h r e a d a t t r i n i t (& a t t r ) ;t e s t e r r n o ( ” p t h r e a d a t t r i n i t ” ) ;

/∗ parametry szeregowania odczytywane z atrybutów ∗/errno = p t h r e a d a t t r s e t i n h e r i t s c h e d (&attr , PTHREAD EXPLICIT SCHED) ;t e s t e r r n o ( ” p t h r e a d a t t r s e t i n h e r i t s c h e d ” ) ;

/∗ wybór podanego algorytmu szeregowania ∗/errno = p t h r e a d a t t r s e t s c h e d p o l i c y (&attr , s c h e d p o l i c y ) ;t e s t e r r n o ( ” p t h r e a d a t t r s e t s c h e d p o l i c y ” ) ;

/∗ utworzenie k i l k u wątków wątku z różnymi p r i o r y t e t a m i ∗/for ( i =0; i < N; i++) {

/∗ k o l e j n e wątk i mają coraz wyższe p r i o r y t e t y ∗/sp . s c h e d p r i o r i t y = pmin + (pmax−pmin ) ∗ i /( f loat ) (N−1) ;arg [ i ] . p r z e r w i j = 0 ;arg [ i ] . l i c z n i k = 0 ;arg [ i ] . p r i o r y t e t = sp . s c h e d p r i o r i t y ;

/∗ u s t a w i e n i e p r i o r y t e t u ∗/errno = pthread at t r s e t schedparam(&attr , &sp ) ;t e s t e r r n o ( ” pthread at t r s e t schedparam ” ) ;

99

6.2. WYKAZ PRZYKŁADÓW

/∗ uruchomienie wątku ∗/errno = pthread c r ea t e (& id [ i ] , &att r , watek , &arg [ i ] ) ;t e s t e r r n o ( ” pth r ead c r ea t e ” ) ;

p r i n t f ( ”utworzono wątek #%d o p r i o r y t e c i e %d\n” , i , arg [ i ] . p r i o r y t e t ) ;}

errno = p t h r e a d a t t r d e s t r o y (& a t t r ) ;t e s t e r r n o ( ” p t h r e a d a t t r d e s t r o y ” ) ;

/∗ oczek iwanie ∗/s l e e p (2 ) ;

/∗ u s t a w i e n i e f l a g i zakończenia pracy , k tór ą t e s t u j ą f u n k c j e wątkóworaz od czy t i c h b i e ż ą c y c h l i c z n i k ó w ∗/

for ( i =0; i < N; i++) {arg [ i ] . p r z e r w i j = 1 ;p r i n t f ( ”wątek #%d ( p r i o r y t e t %3d) : l i c z n i k = %d\n” ,

i ,arg [ i ] . p r i o r y t e t ,arg [ i ] . l i c z n i k

) ;}

/∗ t e r a z oczek iwanie na i c h zakończen ie ∗/for ( i =0; i < N; i++) {

errno = p t h r e a d j o i n ( id [ i ] , NULL) ;t e s t e r r n o ( ” p t h r e a d j o i n ” ) ;

}

return EXIT SUCCESS ;}//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

100

Funkcje

Linuxpthread attr getaffinity np, 50pthread attr setaffinity np, 50pthread cleanup pop restore np, 50pthread cleanup push defer np, 50pthread getaffinity np, 50pthread getattr np, 50pthread setaffinity np, 50pthread timedjoin np, 50pthread tryjoin np, 50pthread yield, 50

Pozostałeperror, 7sched get priority max, 17sched get priority min, 17sched yield, 50strerror, 7

pthread atfork, 25, 25pthread attr, 14pthread attr destroy, 14, 14pthread attr get, 14pthread attr getdetachstate, 14, 14pthread attr getguardsize, 16pthread attr getinheritsched, 16pthread attr getschedpolicy, 16pthread attr getscope, 18pthread attr getstack, 15pthread attr getstackaddr, 15pthread attr getstacksize, 15pthread attr init, 14, 14pthread attr set, 14pthread attr setdetachstate, 14, 14pthread attr setguardsize, 16pthread attr setinheritsched, 16pthread attr setschedpolicy, 16pthread attr setscope, 18pthread attr setstack, 15pthread attr setstackaddr, 15pthread attr setstacksize, 15pthread barrier destroy, 44, 44pthread barrier init, 44, 44pthread barrier wait, 45, 45pthread barrierattr destroy, 44

pthread barrierattr getpshared, 44pthread barrierattr init, 44pthread barrierattr setpshared, 44pthread cancel, 23, 24pthread cleanup pop, 20, 20pthread cleanup push, 20, 20pthread cond broadcast, 39, 39pthread cond destroy, 37, 38pthread cond init, 37, 38pthread cond signal, 39, 39pthread cond timedwait, 38, 39, 39pthread cond wait, 39, 39pthread condattr destroy, 38pthread condattr getclock, 39pthread condattr getpshared, 38pthread condattr init, 38pthread condattr setclock, 38pthread condattr setpshared, 38pthread create, 10, 10, 11, 12, 16pthread detach, 12, 12pthread equal, 10, 11pthread exit, 11, 20pthread getconcurrency, 26pthread getcpuclockid, 26, 26pthread getschedparam, 17pthread getspecific, 21pthread join, 11, 11, 12, 50pthread key create, 21, 21pthread key delete, 21pthread kill, 23, 23pthread mutex create, 31pthread mutex destroy, 31, 31pthread mutex getprioceiling, 36pthread mutex init, 31pthread mutex lock, 32, 32, 34pthread mutex setprioceiling, 36, 36pthread mutex timedlock, 32, 32pthread mutex timedwait, 39pthread mutex trylock, 32, 32pthread mutex unlock, 34pthread mutexattr destroy, 35pthread mutexattr getprioceiling, 36pthread mutexattr getprotocol, 36

101

FUNKCJE

pthread mutexattr getpshared, 35pthread mutexattr gettype, 35pthread mutexattr init, 35pthread mutexattr setprioceiling, 36, 36pthread mutexattr setprotocol, 36pthread mutexattr setpshared, 35pthread mutexattr settype, 35pthread once, 22, 22pthread rwlock destroy, 41, 41pthread rwlock init, 41, 41pthread rwlock rdlock, 42pthread rwlock timedrdlock, 42pthread rwlock timedwrlock, 42pthread rwlock tryrdlock, 42pthread rwlock trywrlock, 42pthread rwlock unlock, 42, 42pthread rwlock wrlock, 42pthread rwlockattr destroy, 41, 41pthread rwlockattr getpshared, 41, 41pthread rwlockattr init, 41, 41pthread rwlockattr setpshared, 41, 41pthread self, 10, 11pthread setcancelstate, 23, 24pthread setcanceltype, 24, 24pthread setconcurrency, 26pthread setschedparam, 17pthread setspecific, 21pthread sigmask, 22, 22pthread spin destroy, 46pthread spin init, 46pthread spin lock, 46pthread spin trylock, 46pthread spin unlock, 46pthread testcancel, 24pthread testcancel(void), 23pthread unlock, 32, 34

102

Typy

pthread attr t, 10, 14pthread barrier t, 44pthread barrierattr t, 44pthread cond t, 37, 38pthread condattr t, 38pthread key t, 21pthread mutex t, 31pthread mutexattr t, 31, 35pthread once t, 22pthread rwlock t, 41pthread rwlockattr t, 41pthread spinlock t, 46pthread t, 10

103

Stałe

CLOCK THREAD CPUTIME ID, 26

PAGE SIZE, 15PTHREAD BARRIER SERIAL THREAD, 45PTHREAD CANCEL ASYNCHRONOUS, 24PTHREAD CANCEL DEFERRED, 24PTHREAD CANCEL DISABLE, 24PTHREAD CANCEL ENABLE, 23, 24PTHREAD CANCELED, 11PTHREAD COND INITIALIZER, 37PTHREAD CREATE DETACHED, 14PTHREAD CREATE JOINABLE, 14PTHREAD EXPLICIT SCHED, 16PTHREAD INHERIT SCHED, 16PTHREAD KEY MAX, 21PTHREAD MUTEX INITIALIZER, 31PTHREAD ONCE INIT, 22PTHREAD PRIO INHERIT, 35, 36PTHREAD PRIO NONE, 35, 36PTHREAD PRIO PROTECT, 35, 36PTHREAD PROCESS PRIVATE, 38, 41, 44,

46, 47PTHREAD PROCESS SHARED, 38, 41, 44, 46,

47PTHREAD SCOPE PROCESS, 18PTHREAD SCOPE SYSTEM, 18

SCHED FIFO, 16SCHED OTHER, 16SCHED RR, 16SCHED SPORADIC, 16, 17

104

Definicje preprocesora

POSIX C SOURCE, 54POSIX THREAD CPUTIME, 26

PTHREAD STACK MIN, 15PTHREAD THREADS MAX, 10

105