Plan wykładu. Obliczenia równoległe w zagadnieniach inżynierskich. Wykład 1 p. Wzajemne wykluczanie. Procesy współbieżne

Podobne dokumenty
Plan wykładu. Programowanie aplikacji równoległych i rozproszonych. Wykład 1 p. Wzajemne wykluczanie. Procesy współbieżne

Programowanie aplikacji równoległych i rozproszonych. Wykład 1

Temat zajęć: Tworzenie i obsługa wątków.

Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

w odróżnieniu od procesów współdzielą przestrzeń adresową mogą komunikować się za pomocą zmiennych globalnych

Procesy i wątki. Krzysztof Banaś Obliczenia równoległe 1

Podstawy programowania współbieżnego. 1. Wprowadzenie. 2. Podstawowe pojęcia

Programowanie równoległe i rozproszone. W1. Wielowątkowość. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Programowanie Współbieżne

Wielowątkowy serwer TCP

1. Uruchom poniższy program tworzący pojedynczy wątek:

Przetwarzanie wielowątkowe przetwarzanie współbieżne. Krzysztof Banaś Obliczenia równoległe 1

Programowanie współbieżne Wykład 10 Synchronizacja dostępu do współdzielonych zasobów. Iwona Kochańska

Jędrzej Ułasiewicz Programownie aplikacji współbieżnych str. 1. Wątki

Problemy współbieżności

Jędrzej Ułasiewicz Programownie aplikacji współbieżnych str. 1. Wątki

Wykład 3. Procesy i wątki. Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Jędrzej Ułasiewicz Programownie aplikacji współbieżnych str. 1. Wątki

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Wprowadzenie do programowania współbieżnego

Mariusz Rudnicki PROGRAMOWANIE WSPÓŁBIEŻNE I SYSTEMY CZASU RZECZYWISTEGO CZ.4

Podstawy programowania skrót z wykładów:

Dzisiejszy wykład. Klasa string. wersja prosta wersja ze zliczaniem odwołań. Wyjątki Specyfikator volatile Semafory

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Zaawansowane programowanie w C++ (PCP)

Wstęp do programowania

Tworzenie programów równoległych cd. Krzysztof Banaś Obliczenia równoległe 1

Współbieżność w środowisku Java

Tworzenie wątków. #include <pthread.h> pthread_t thread;

Wielozadaniowość w systemie Microsoft Windows

Mariusz Rudnicki PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO CZ.4

Problemy czytelników i pisarzy oraz 5 ucztujących filozofów

Kurs programowania. Wykład 8. Wojciech Macyna

procesów Współbieżność i synchronizacja procesów Wykład prowadzą: Jerzy Brzeziński Dariusz Wawrzyniak

Prof. Danuta Makowiec Instytut Fizyki Teoretycznej i Astrofizyki pok. 353, tel danuta.makowiec at gmail.com

Pojęcia podstawowe. Oprogramowanie systemów równoległych i rozproszonych. Wykład 1. Klasyfikacja komputerów równoległych I

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Wątki. S. Samolej: Wątki 1

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

Unix: programowanie z użyciem w atków

Unix: programowanie z użyciem w atków

Implementacje zgodne z tym standardem są nazywane wątkami POSIX lub Pthreads.

4. Procesy pojęcia podstawowe

Problemy czytelników i pisarzy oraz 5 ucztujących filozofów

Szablony funkcji i szablony klas

Programowanie współbieżne Wykład 7. Iwona Kochaoska

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Część 4 życie programu

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

Wykład 5. Synchronizacja (część II) Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Procesy. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 9 października 2011

SYSTEMY CZASU RZECZYWISTEGO - VxWorks

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

procesy odrębne dzielone

Mechanizmy pracy równoległej. Jarosław Kuchta

Programowanie współbieżne Wykład 9 Synchronizacja dostępu do współdzielonych zasobów. Iwona Kochańska

Oprogramowanie i wykorzystanie stacji roboczych. Wykład 4

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Systemy Operacyjne 2: Wątki pthreads. dr inż. Arkadiusz Chrobot

Problem producentakonsumenta

UŻYCIE I ZARZĄDZANIE WĄTKAMI

Gdy kilka procesów czyta a przynajmniej jeden dokonuje zapisu wynik odczytu zależeć może od sposobu realizacji przeplotu.

9. Problem wzajemnego wykluczania i sekcji krytycznej

Języki i techniki programowania Ćwiczenia 2

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

WĄTKI W SYSTEMIE LINUX

UŻYCIE I ZARZĄDZANIE WĄTKAMI

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

z powielaniem wielu struktur danych oraz komunikacja

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

4. Procesy pojęcia podstawowe

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Programowanie w języku C++

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Wstęp do Programowania 2

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Wstęp do programowania

I.Wojnicki, Tech.Inter.

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

Programowanie C++ Wykład 2 - podstawy języka C++ dr inż. Jakub Możaryn. Warszawa, Instytut Automatyki i Robotyki

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Informatyka I. Wykład 3. Sterowanie wykonaniem programu. Instrukcje warunkowe Instrukcje pętli. Dr inż. Andrzej Czerepicki

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

Programowanie w C++ Wykład 2. Katarzyna Grzelak. 4 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 44

Wstęp do Programowania, laboratorium 02

Architektury systemów równoległych

Procesy, wątki i zasoby

Globalne / Lokalne. Wykład 15. Podstawy programowania (język C) Zmienne globalne / lokalne (1) Zmienne globalne / lokalne (2)

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Transkrypt:

Plan wykładu Obliczenia równoległe w zagadnieniach inżynierskich Wykład 1 Podstawowe pojęcia i model programowania Sposoby realizacji watków w systemach operacyjnych Tworzenie watów i zarzadzanie nimi Sposoby realizacji synchronizacji watków Metody rozwiazań przykładowych problemów Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska 1/43 Wykład 1 p Procesy współbieżne Wzajemne wykluczanie Mówimy, że dwa procesy sa współbieżne, jeśli jeden z nich rozpoczyna się przed zakończeniem drugiego. W systemach jednoprocesorowych czas pracy procesora jest dzielony pomiędzy wszystkie wykonywane współbieżnie procesy poprzez wykorzystanie zasady podziału czasu. Jeśli w systemie komputerowym jest wiele procesorów, moga one wykonywać różne procesy jednocześnie. Uzależnione procesy moga ze soba współpracować lub współzawodniczyć. Praca takich procesów wymaga synchronizacji. Obiekt, z którego może korzystać w sposób wyłaczny wiele procesów, nazywa się zasobem dzielonym. Fragment procesu w którym korzysta on z obiektu dzielonego, nazywa się sekcja krytyczna tego procesu. Problem wzajemnego wykluczania: zsynchronizować N procesów, z których każdy w nieskończonej pętli na przemian zajmuje się własnymi sprawami i wykonuje sekcję krytyczna, w taki sposób, aby wykonanie jakichkolwiek dwóch lub więcej procesów nie pokrywało się w czasie. Rozwiazanie problemu wzajemnego wykluczania - dodanie instrukcji poprzedzajacych sekcję krytyczna (protokół wstępny), oraz następujacych bezpośrednio po sekcji krytycznej (protokół końcowy). 3/43 Wykład 1 p

Bezpieczeństwo i żywotność Blokada i zagłodzenie Poprawność programu sekwencyjnego: częściowa poprawność - jeśli się zatrzyma, to zwróci dobre wyniki, własność stopu - w ogóle się zatrzyma. Własność bezpieczeństwa - program współbieżny jest bezpieczny jeśli nigdy nie doprowadza do niepożadanego stanu (nigdy swa procesy nie znajda się jednocześnie w swoich sekcjach krytycznych). Własność żywotności zapewnia, że każde pożadane zdarzenie w końcu zajdzie (jeśli jakiś proces czeka na wejście do swojej sekcji krytycznej, do w końcu do niej wejdzie). Sprawiedliwość. Blokada (zastój, zakleszczenie lub martwy punkt) - Zbiór procesów znajduje się w stanie blokady, jeśli każdy z tych procesów jest wstrzymywany w oczekiwaniu na zdarzenie, które może być spowodowane przez jakiś inny proces z tego zbioru. Zagłodzenie (wykluczenie) - proces nie zostaje wznowiony, mimo że zdarzenie na które czeka, występuje dowolna ilość razy (za każdym razem gdy proces ten mógłby być wznowiony, jest wybierany jakiś inny proces). 5/43 Wykład 1 p Watek - definicja Własności watków Watek (thread) można określić jako pojedyncza sekwencję sterowania wewnatrz procesu (podstawowa jednostka użycia procesora). Watek wykonuje niezależny ciag instrukcji, który może być szeregowany do wykonania przez system operacyjny. Środowiskiem do wykonywania watku jest proces. Tradycyjna implementacja procesu ma jeden watek sterowania. W nowszych systemach dopuszcza się istnienie wielu watków wewnatrz procesu. Koszt utworzenia i przełaczenia watku jest mniejszy niż procesu. Dane statyczne procesu sa dla watków działajacych w ramach jednego procesu wzajemnie widoczne. Wykonanie każdego watku przebiega sekwencyjnie; każdy watek ma swój licznik rozkazów. Watki moga być wykonywane na oddzielnych procesorach, co umożliwia przyspieszenie obliczeń. Ponieważ watki dziela wspólne dane konieczna jest synchronizacja dostępu do tych wspólnych danych. 7/43 Wykład 1 p

Typy watków Biblioteka Pthreads Ze względu na sposób implementacji rozróżnia się następujace typy watków: Watki poziomu jadra (kernel-space threads) sa implementowane poprzez dołaczenie do każdego procesu tabeli jego watków. System zarzadza każdym watkiem wykorzystujac kwant czasu przyznany dla jego procesu rodzica (funkcja clone). Watki poziomu użytkownika (user-space threads). Rezygnacja z zarzadzania watkami przez jadro. W procesie jest definiowany zbiór wykonalnych procedur, które sa wymieniane poprzez operacje na wskaźniku stosu. Dwupoziomowy (hybrydowy) system watków (two-level threads). Połaczenie systemu watków poziomu użytkownika i jadra. Zestaw funkcji dotyczacy watków zdefiniowany został przez normę POSIX P1003.4a i nosi nazwę Pthreads (skrót od POSIX threads). Jest to zbiór typów i funkcji języka C. Implementacja pakietu istnieje między innymi w systemach Linux, QNX6, DEC OSF1. Obecnie watki sa częścia biblioteki glibc (od wersji 2). 9/43 Zasoby watku Watki POSIX - grupy funkcji Watek korzysta z zasobów procesu, ale może być szeregowany do wykonania jako niezależna jednostka w ramach procesu. Ma swój własny przebieg i własne zasoby lokalne: stos, rejestry, sposób kolejkowania (szeregowania): np. priorytet, zbiór sygnałów, lokalne dane watku. Pozostałe zasoby watki dziela ze soba w ramach procesu - pamięć, instrukcje programu, ID procesu, deskryptory plików, dzielone biblioteki, mechanizmy komunikacji międzyprocesorowej, itd. Funkcje realizujace watki POSIX można podzielić na trzy grupy: Zarzadzanie watkami - funkcje do tworzenia, zarzadzania, usuwania watków, oraz funkcje zwiazane z atrybutami watków. Obiekty mutex - funkcje realizujace synchronizacje dostępu do zasobów ( MUTual EXclusion - wzajemne wykluczanie). Funkcje zapewniaja tworzenie, usuwanie, otwieranie i zamykanie obiektów mutex. Zmienne warunkowe - funkcje realizujace komunikację między watkami dzielacymi obiekty mutex. Wykorzystuja warunki zdefiniowane przez programistę. Sa to funkcje do tworzenia, usuwania, czekania i wysyłania sygnału przy określonej wartości zmiennej. 11/43

Konwencja nazw Tworzenie watku (I) Przedrostek funkcji pthread pthread_attr pthread_mutex pthread_mutexattr pthread_cond pthread_condattr pthread_key Grupa funkcji Funkcje watków oraz funkcje pomocnicze Atrybuty watków Obiekty mutex Atrybuty obiektów mutex Zmienne warunkowe Atrybuty zmiennych warunkowych Specyficzne dla watku klucze (dane lokalne) Do uruchomienia nowego watku służy funkcja pthread_create: int pthread_create(pthread_t *thread, pthread_attr_t *attr, void* (* func)(void *), void *arg) Utworzony watek wykonuje kod funkcji fun, której adres został przekazany poprzez trzeci parametr wywołania funkcji. Do funkcji wykonywanej przez watek można przekazać dane za pomoca parametru arg. Poprzez pierwszy parametr zwracany jest identyfikator watku (jest on wykorzystywany do określania watku w innych funkcjach standardu pthreads). 13/43 Tworzenie watku (II) Zakończenie działania watku Funkcja wykonywana przez watek powinna mieć postać: void *f(void *arg); Przykład: void *run(void *arg) int main(int argc, char** argv) pthread_t threadid; if (pthread_create(&threadid, NULL, run, NULL)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; Watek może być zakończony w następujacy sposób: Następuje powrót z funkcji wykonywanej przez watek, Watek wywoła funkcje pthread_exit(). Watek zostaje odwołany przez inny watek za pomoca funkcji pthread_cancel(), Cały proces zostaje zakończony przez wywołanie funkcji exit() czy exec(), lub watek główny zostanie zakończony poprzez wywołanie return w funkcji main(). 15/43

Kończenie watku - zasoby Oczekiwanie na zakończenie watku Możliwe sa dwa sposoby postępowania z zasobami zakończonych watków: Z chwila zakończenia watku zwalniane sa wszystkie jego zasoby. Zasoby zwalniane sa z chwila dołaczenia bieżacego watku do innego watku (który wywołał funkcję pthread_join). Ustawienie sposobu postępowania z zasobami watków po ich zakończeniu jest możliwe poprzez atrybuty watku lub za pomoca funkcji pthread_detach(). Watek może oczekiwać na zakończenie działania innego watku przez wywołanie funkcji pthread_join. int pthread_join(pthread_t thread_id, void **thread_return) thread_id - identyfikator watku na zakończenie którego będzie czekał wołajacy watek, thread_return - jeśli jest różny od NULL, to wówczas kod zakończenia watku thid zostanie wstawiony pod adres wskazywany przez thread_return. Kodem zakończenia może być też wartość określona przy wołaniu funkcji pthread_exit lub PTHREAD_CANCELLED jeśli watek został usunięty. Watek do którego jest dołaczany dany watek musi być w stanie umożliwiajacym dołaczenie. Funkcja pthread_join powinna być wykonana dla każdego nie odłaczonego watku. 17/43 Zasoby watków - przykład Tworzenie watków - przykład (I) pthread_create() Zakonczenie pthread_exit() pthread_join() W1 i W2 ustawiony atrybut PTHREAD_CREATE_JOINABLE Zwolnienie zasobów W3 i W4 ustawiony atrybut PTHREAD_CREATE_DETACHED Zakonczenie i zwolnienie zasobów #include <pthread.h> #include <unistd.h> #include <iostream> void* NewThread(void* arg) int id = *static_cast<int*>(arg); for (int i = 0; i < 3; i++) std::cout << id << " " << std::flush; sleep(1); return NULL; 19/43

Tworzenie watków - przykład (II) Tworzenie watków - przykład (III) int main() pthread_t thread; int id1 = 1; if (pthread_create(&thread, NULL, NewThread, (void *)(&id1))) std::err << "błąd podczas tworzenia wątku nr 1" << std::endl; pthread_detach(thread); Kompilacja: g++ -o watki watki.cpp -lpthread lub g++ -pthread -o watki watki.cpp Wynik działania programu: 1 2 1 2 1 2 int id2 = 2; if (pthread_create(&thread, NULL, NewThread, (void *)(&id2))) std::cerr << "błąd podczas tworzenia wątku nr 2" << std::endl; pthread_detach(thread); pthread_exit(null); 21/43 Funkcja pthread_join - przykład (I) Funkcja pthread_join - przykład (II) #include <pthread.h> #include <iostream> #include <unistd.h> #include <fstream> const int size = ; void * SaveThread(void * arg) std::cout << "Begin Thread" << std::endl; ofstream os("ala.txt"); for (int i = 0; i < size; i++) os << "0"; std::cout << "End Thread" << std::endl; return NULL; int main() std::cout << "Begin Program" << std::endl; pthread_t thread; if (pthread_create(&thread, NULL, SaveThread, NULL)) cerr << "błąd podczas tworzenia wątku" << std::endl; for (int i = 0; i < 30; i++) sleep(1); std::cout << i << " " << flush; void* result; pthread_join(thread, &result); std::cout << std::endl << "End program \n" << std::endl; pthread_exit(null); 23/43

Funkcja pthread_join - przykład (III) Obiekty mutex Wynik działania programu dla size = 50000000: Begin Program Begin Thread 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 End Thread End program Wynik działania programu dla size = 5000000: Begin Program Begin Thread 0 1 2 3 4 5 End Thread 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 End program Mutex jest mechanizmem wzajemnego wykluczania ( MUTual EXclusion ) służacych do ochrony danych wspólnych dla watków przed jednoczesnymi modyfikacjami. Mechanizm ten może służyć do implementacji sekcji krytycznych, semaforów i monitorów. Mutex ma dwa stany: otwarty - nie zajęty przez żaden watek, zajęty - zajęty przez jeden watek. Mutex nie może być jednocześnie zajęty przez więcej niż jeden watek. Watek próbujacy zajać już zajęty watek zostaje wstrzymany do chwili zwolnienia mutexu przez watek, który go zajał wcześniej. 25/43 Zajęcie i zwolnienie obiektu mutex Obiekty mutex - przykład Na obiekcie mutex wykonuje się dwie podstawowe operacje: zajęcie i zwolnienie obiektu mutex. Do zajęcia obiektu mutex służy funkcja pthread_mutex_lock, natomiast do zwolnienia funkcja pthread_mutex_unlock. Jako parametr przyjmuja one wskaźnik do wcześniej utworzonego obiektu mutex. Thread 1 Thread 2 mutex_lock(mutex) uzycie zasobu mutex_unlock(mutex) mutex_lock(mutex) uzycie zasobu blokada odblokowanie // utworzenie i zainicjowanie muteksu pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void * run(void * arg) pthread_mutex_lock(&mutex); // zajęcie muteksu - protokół wstępny // operacje na zasobie dzielonym - sekcja krytyczna pthread_mutex_unlock(&mutex); // zwolnienie muteksu- protokół końcowy mutex_unlock(mutex) 27/43

Operacje na obiektach mutex - przykład (I) Operacje na obiektach mutex - przykład (II) #include <pthread.h> #include <iostream> #include <unistd.h> const int size = 100; int sum = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void * ForThread(void * arg) int* tab = static_cast< int* >(arg); for (int i = 0; i < size/2; i++) pthread_mutex_lock(&mutex); sum += tab[i]; pthread_mutex_unlock(&mutex); return NULL; 29/43 int main() pthread_t thread1, thread2; int tab[size]; for (int j = 0; j < size; j++) tab[j] = j; if (pthread_create(&thread1, NULL, ForThread, tab)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; if (pthread_create(&thread2, NULL, ForThread, tab+size/2)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; pthread_join(thread1, NULL); pthread_join(thread2, NULL); std::cout << "Suma: " << sum << std::endl; return 0; Zmienne warunkowe (I) Oczekiwanie na spełnienie warunku Zmienne warunkowe sa mechanizmem umożliwiajacym zawieszenie i zwolnienie czasu procesora (watku) do momentu, w którym zostanie spełniony określony warunek. Warunek ten może być dowolny i niezależny od zmiennej warunkowej, np. osiagnięcie przez zmienna określonej wartości. Zmienna warunkowa musi być zawsze otoczona obiektem mutex, aby uniknać jednoczesnej próby oczekiwania i sygnalizowania na zmiennej warunkowej. Przed wykorzystaniem zmienna warunkowa musi zostać odpowiednio zainicjowana. Do oczekiwania na spełnienie warunku służy funkcja pthread_cond_wait. Funkcja pthread_cond_wait w sposób atomowy zwalnia mutex (tak jak funkcja pthread_mutex_unlock) i oczekuje na sygnał o spełnienie zmiennej warunkowej cond. Wykonanie watku jest zawieszone i nie zajmuje on czasu procesora aż do momentu odebrania sygnału od zmiennej warunkowej. Mutex musi być zajęty przez watek wywołujacy pthread_cond_wait. Przed końcem działania pthread_cond_wait zajmuje mutex. 31/43

Zmienne warunkowe - przykład użycia Zmienne warunkowe - przykład (I) Watek 1 (oczekujacy na warunek): pthread_mutex_lock(&m); pthread_cond_wait(&cond, &m); pthread_mutex_unlock(&m); Watek 2 (sygnalizujacy spełnienie warunku): pthread_mutex_lock(&m); pthread_cond_signal(&cond); pthread_mutex_unlock(&m); blokada odblokowanie Watek 1 Watek 2 mutex_lock(m) cond_wait(c,m) uzycie zasobu mutex_unlock(m) mutex_lock(m) cond_signal(c) mutex_unlock(m) blokada odblokowanie ustawienie warunku odblokowanie int number; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void* RandomThread(void* arg) srandom(1); for (int i=0; i<20; i++) pthread_mutex_lock(&mutex); number = static_cast<double>(rand())/rand_max*10; if (number < 5) std::cout << "mniejsza"; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex); sleep(1); 33/43 Zmienne warunkowe - przykład (II) Zmienne warunkowe - przykład (III) void* OutputThread(void* arg) while (true) pthread_mutex_lock(&mutex); pthread_cond_wait(&cond, &mutex); std::cout << "Wygenerowana liczba - " << number << " jest mniejsza od 5" << std::endl; pthread_mutex_unlock(&mutex); int main() pthread_t thread1; if (pthread_create(&thread1, NULL, RandomThread, NULL)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; pthread_t thread2; if (pthread_create(&thread2, NULL, OutputThread, NULL)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; void* result; pthread_join(thread1, &result); pthread_cancel(thread2); pthread_exit(null); 35/43

Jednokrotne wykonanie Jednokrotna inicjalizacja - przykład (I) Wywołanie funkcji pthread_once daje pewność, że dany kod zostanie wykonany tylko przez jeden (pierwszy) watek, pomimo, że funkcja ta będzie wywoływana przez wiele watków. Funkcja ta może zostać wykorzystana np. do inicjalizacji zmiennych wspólnych dla watków. int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)); once_control - zainicjowana zmienna typu pthread_once_t, init_routine - funkcja jaka ma zostać wykonana. Zmienna once_control musi być przed użyciem zainicjowana: pthread_once_t once_control = PTHREAD_ONCE_INIT; #include <pthread.h> #include <iostream.h> #include <unistd.h> pthread_once_t initcontrol = PTHREAD_ONCE_INIT; void Init() std::cout << "Initializacja zostala wykonana " << "przez watek o identyfikatorze " << pthread_self() << std::endl; void * Thread(void * arg) std::cout << "Thread - " << pthread_self() << std::endl; pthread_once(&initcontrol, Init); return NULL; 37/43 Jednokrotna inicjalizacja - przykład (II) Jednokrotna inicjalizacja - pętla int main() pthread_t thread[3]; for (int i = 0; i < 3; i++) if (pthread_create(thread + i, NULL, Thread, NULL)) for (int i = 0; i < 3; i++) pthread_join(thread + i, NULL); return 0; Wynik działania programu: Thread - 1026 Initializacja zostala wykonana przez watek o identyfikatorze 1026 Thread - 2051 Thread - 3074 39/43 bool init = true; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void* run(void * arg) pthread_mutex_lock(&mutex); if (!init) // kod wykonywany tylko przez jeden wątek init = false; else init = true; pthread_mutex_unlock(&mutex);

Bramki Bramki - przykładowa implementacja (I) Poczawszy od wersji IEEE Std 1003.1-2001 standardu wprowadzono funkcje implementujace bramki (barrier). Biblioteka glibc posiada implementacje bramek poczawszy od wersji 2.2. Synchronizacja przy użyciu bramek polega na wstrzymaniu watków aż do momentu, w którym wszystkie watki osiagn a dany punkt synchronizacji (służy do tego funkcja pthread_barrier_wait). Poniżej przedstawiono przykładowa implementację bramek przy użyciu zmiennych warunkowych (bramek oczywiście nie trzeba implementować - sa już w standardzie): struct pthread_barrier_t int nthreads; // liczba watkow do wstrzymywania pthread_mutex_t mutex; pthread_cond_t cond; int nwaiting; // liczba aktualnie czekajacych watkow ; 41/43 inline int pthread_barrier_init(pthread_barrier_t* barrier, void*, int nthreads) barrier->nthreads = nthreads; barrier->nwaiting = nthreads - 1; pthread_mutex_init(&barrier->mutex, NULL); pthread_cond_init(&barrier->cond, NULL); return 0; Bramki - przykładowa implementacja (II) inline void pthread_barrier_destroy(pthread_barrier_t* barrier) pthread_mutex_destroy(&barrier->mutex); pthread_cond_destroy(&barrier->cond); inline void pthread_barrier_wait(pthread_barrier_t* barrier) pthread_mutex_lock(&barrier->mutex); if (barrier->nwaiting) barrier->nwaiting--; pthread_cond_wait(&barrier->cond, &barrier->mutex); else barrier->nwaiting = barrier->nthreads - 1; pthread_cond_broadcast(&barrier->cond); pthread_mutex_unlock(&barrier->mutex); 43/43