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

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

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

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

Programowanie Współbieżne

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

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

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

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

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

Wielowątkowy serwer TCP

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

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

Problemy współbieżności

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

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

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

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

Mariusz Rudnicki PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO CZ.4

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

Wprowadzenie do programowania współbieżnego

Zaawansowane programowanie w C++ (PCP)

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

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

Unix: programowanie z użyciem w atków

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

Unix: programowanie z użyciem w atków

Wstęp do programowania

Wielozadaniowość w systemie Microsoft Windows

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

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

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

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

Kurs programowania. Wykład 8. Wojciech Macyna

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

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

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

4. Procesy pojęcia podstawowe

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

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

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

WĄTKI W SYSTEMIE LINUX

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

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

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

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

Programowanie w języku C++

Część 4 życie programu

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

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

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

synchronizacji procesów

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

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

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

synchronizacji procesów

5. Model komunikujących się procesów, komunikaty

4. Procesy pojęcia podstawowe

Języki i techniki programowania Ćwiczenia 2

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

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Problem producentakonsumenta

POSIX Threads. Wojciech Muła. marzec 2010 z późniejszymi poprawkami (plik utworzony 21 marca 2011)

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

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

SYSTEMY CZASU RZECZYWISTEGO - VxWorks

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

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

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

Architektury systemów równoległych

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Wstęp do Programowania 2

procesy odrębne dzielone

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

9. Problem wzajemnego wykluczania i sekcji krytycznej

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

z powielaniem wielu struktur danych oraz komunikacja

Procesy, wątki i zasoby

Szablony funkcji i szablony klas

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

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

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

Oprogramowanie i wykorzystanie stacji roboczych. Wykład 4

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

Wykład 4: Klasy i Metody

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia

Zaawansowane programowanie w języku C++ Zarządzanie pamięcią w C++

Wstęp do programowania

Wstęp do Programowania, laboratorium 02

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

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

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

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Programowanie współbieżne i rozproszone

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

UŻYCIE I ZARZĄDZANIE WĄTKAMI

Synchronizacja procesów i wątków

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

Tablice, funkcje - wprowadzenie

Transkrypt:

Wykład 1 p. 1/52 Programowanie aplikacji równoległych i rozproszonych Wykład 1 Dr inż. Tomasz Olas olas@icis.pcz.pl Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska

Plan wykładu Wykład 1 p. 2/52 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

Procesy współbieżne Wykład 1 p. 3/52 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.

Wzajemne wykluczanie Wykład 1 p. 4/52 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).

Bezpieczeństwo i żywotność Wykład 1 p. 5/52 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 i zagłodzenie Wykład 1 p. 6/52 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).

Watek - definicja Wykład 1 p. 7/52 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.

Własności watków Wykład 1 p. 8/52 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.

Typy watków Wykład 1 p. 9/52 Ze względu na sposób implementacji rozróżnia się następujace typy watków: Watki poziomu j adra (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.

Wykład 1 p. 10/52 Biblioteka Pthreads 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).

Zasoby watku Wykład 1 p. 11/52 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.

Watki POSIX - grupy funkcji Wykład 1 p. 12/52 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 realizuj ace 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.

Wykład 1 p. 13/52 Konwencja nazw 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)

Tworzenie watku (I) Wykład 1 p. 14/52 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).

Wykład 1 p. 15/52 Tworzenie watku (II) 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;

Zakończenie działania watku Wykład 1 p. 16/52 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 atek główny zostanie zakończony exit() czy exec(), lub w poprzez wywołanie return w funkcji main().

Kończenie watku - zasoby Wykład 1 p. 17/52 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().

Oczekiwanie na zakończenie watku Wykład 1 p. 18/52 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.

Wykład 1 p. 19/52 Zasoby watków - przykład W1 i W2 ustawiony atrybut PTHREAD_CREATE_JOINABLE W3 i W4 ustawiony atrybut PTHREAD_CREATE_DETACHED pthread_create(...) Zakonczenie pthread_exit(...) pthread_join(...) Zakonczenie i zwolnienie zasobów Zwolnienie zasobów

Tworzenie watków - przykład (I) Wykład 1 p. 20/52 #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;

Tworzenie watków - przykład (II) Wykład 1 p. 21/52 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; exit(1); pthread_detach(thread); int id2 = 2; if (pthread_create(&thread, NULL, NewThread, (void *)(&id2))) std::cerr << "błąd podczas tworzenia wątku nr 2" << std::endl; exit(1); pthread_detach(thread); pthread_exit(null);

Wykład 1 p. 22/52 Tworzenie watków - przykład (III) Kompilacja: g++ -o watki watki.cpp -lpthread lub g++ -pthread -o watki watki.cpp Wynik działania programu: 1 2 1 2 1 2

Funkcja pthread_join - przykład (I) Wykład 1 p. 23/52 #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;

Funkcja pthread_join - przykład (II) Wykład 1 p. 24/52 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; exit(1); 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);

Wykład 1 p. 25/52 Funkcja pthread_join - przykład (III) 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

Obiekty mutex Wykład 1 p. 26/52 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.

Zajęcie i zwolnienie obiektu mutex Wykład 1 p. 27/52 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 mutex_unlock(mutex)

Obiekty mutex - przykład Wykład 1 p. 28/52 // 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...

Operacje na obiektach mutex - przykład (I) Wykład 1 p. 29/52 #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;

Operacje na obiektach mutex - przykład (II) 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; exit(1); if (pthread_create(&thread2, NULL, ForThread, tab+size/2)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; exit(1); pthread_join(thread1, NULL); pthread_join(thread2, NULL); std::cout << "Suma: " << sum << std::endl; return 0; Wykład 1 p. 30/52

Zmienne warunkowe (I) Wykład 1 p. 31/52 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.

Zmienne warunkowe (II) Wykład 1 p. 32/52 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.

Wykład 1 p. 33/52 Zmienne warunkowe - przykład użycia 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); Watek 1 Watek 2 mutex_lock(m) mutex_lock(m) blokada blokada odblokowanie cond_wait(c,m) cond_signal(c) odblokowanie ustawienie warunku uzycie zasobu mutex_unlock(m) mutex_unlock(m) odblokowanie

Wykład 1 p. 34/52 Tworzenie zmiennych warunkowych Zmienna warunkowa, to zmienna typu pthread_cond_t. Przed użyciem zmienna warunkowa musi zostać zainicjowana: Statycznie przy pomocy stałej PTHREAD_COND_INITIALIZER: pthread_cond_t cond = PTHREAD_COND_INITIALIZER; Dynamicznie przy pomocy funkcji: int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); cond - wskaźnik do inicjowanej zmiennej warunkowej typu pthread_cond_t, cond_attr - atrybuty zmiennej warunkowej. Gdy NULL przyjęte będa atrybuty domyślne.

Oczekiwanie na sygnał Wykład 1 p. 35/52 Funkcja pthread_cond_wait służy do zawieszenia watku w oczekiwaniu na sygnał: int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex); cond - zadeklarowana i zainicjowana zmienna warunkowa, mutex - wskaźnik do obiektu mutex, którym sa otoczone operacje na zmiennych warunkowych. 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 wołajacy pthread_cond_wait. Przed końcem działania pthread_cond_wait zajmuje mutex.

Sygnalizacja spełnienia warunku Wykład 1 p. 36/52 Funkcja pthread_cond_signal wznawia jeden z watków oczekujacych na sygnał: int pthread_cond_signal(pthread_cond_t * cond); cond - zadeklarowana i zainicjowana zmienna warunkowa. Jeśli żaden z watków nie oczekuje na sygnał, to nic się nie dzieje. Jeśli w oczekiwaniu na sygnał znajduje się więcej watków, to wznawiany jest jeden z nich. Do wznowienia wszystkich oczekujacych na sygnał watków służy funkcja: int pthread_cond_broadcast(pthread_cond_t * cond);

Wykład 1 p. 37/52 Czasowe oczekiwanie na sygnał Do czasowego zawieszenia watku w oczekiwaniu na sygnał służy funkcja: int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime); cond - zadeklarowana i zainicjowana zmienna warunkowa, mutex - mutex, którym jest otoczona zmienna warunkowa, czas jaki watek będzie oczekiwał na sygnał. Funkcja zwraca ETIMEDOUT jeśli sygnał nie wystapił w podanym czasie (abstime).

Skasowanie zmiennej warunkowej Wykład 1 p. 38/52 Do skasowania zmiennej warunkowej i zwolnienia jej zasobów służy funkcja: int pthread_cond_destroy( pthread_cond_t * cond); cond - zadeklarowana i zainicjowana zmienna warunkowa. Funkcja zwraca kod EBUSY jeśli nastapiła próba usunięcia zmiennej warunkowej, na której oczekiwały watki.

Zmienne warunkowe - przykład (I) Wykład 1 p. 39/52 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);

Zmienne warunkowe - przykład (II) Wykład 1 p. 40/52 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);

Zmienne warunkowe - przykład (III) Wykład 1 p. 41/52 int main() pthread_t thread1; if (pthread_create(&thread1, NULL, RandomThread, NULL)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; exit(1); pthread_t thread2; if (pthread_create(&thread2, NULL, OutputThread, NULL)) std::cerr << "błąd podczas tworzenia wątku" << std::endl; exit(1); void* result; pthread_join(thread1, &result); pthread_cancel(thread2); pthread_exit(null);

Odwołanie watku Wykład 1 p. 42/52 Odwołanie jest mechanizmem, który umożliwia zakończenie działania innego watku przez dany watek. Zależnie od ustawień watek, do którego wysłano takie żadanie może je zignorować, uwzględnić to żadanie (zakończyć swoje działanie) natychmiast lub odwlec zakończenie aż do osiagnięcia pierwszego punktu zwanego punktem odwołania. Do wysłania żadania odwołania watku służy funkcja: int pthread_cancel(pthread_t thread); thread - identyfikator watku do którego wysyłane jest żadanie odwołania. Watek może odwołać samego siebie.

Sposób reakcji na żadanie odwołania Wykład 1 p. 43/52 Do zmiany sposobu reakcji na żadanie odwołania watku służa funkcje: int pthread_setcancelstate(int state, int * old_state ); state - nowy typ reakcji: PTHREAD_CANCEL_ENABLE - umożliwia odwołanie, PTHREAD_CANCEL_DISBLE - powoduje ignorowanie przychodzacych żadań odwołania, old_state - poprzez ten argument funkcja może zwrócić poprzedni typ reakcji (o ile nie został przekazany NULL). int pthread_setcanceltype(int type, int * old_type); type - nowy typ reakcji: PTHREAD_CANCEL_ASYNCHRONOUS - powodujacy natychmiastowe zakończenie działania watku w momencie odebrania żadania odwołania. PTHREAD_CANCEL_DEFERRED - utrzymujacy działanie watku, aż do momentu osiagnięcia pierwszego z punktów odwołania. Domyślnie (PTHREAD_CANCEL_ENABLE i PTHREAD_CANCEL_DEFERRED).

Punkty odwołania Wykład 1 p. 44/52 Punkty odwołania sa miejscami w programie, gdzie wykonywany jest test, czy nie przyszło żadanie odwołania watku i w przypadku pozytywnego wyniku testu wykonywane jest odwołanie. Standard POSIX ustala następujace funkcje jako punkty odwołania: pthread_join() pthread_cond_wait() pthread_cond_timedwait() pthread_testcancel() sem_wait() sigwait() Funkcja pthread_testcancel() jest używana w dużych fragmentach kodu, gdy nie ma wywołania funkcji, które sa punktami odwołania.

Wykład 1 p. 45/52 Identyfikatory watków Funkcja pthread_self zwraca unikalny identyfikator watku przydzielony mu przez system: pthread_t pthread_self(void); Do porównania identyfikatorów dwóch watków służy funkcja: int pthread_equal(pthread_t thread1, pthread_t thread2); thread1 - identyfikator pierwszego watku, thread2 - identyfikator drugiego watku. Funkcja zwraca niezerowa wartość jeśli oba identyfikatory odnosza się do tego samego watku, w przeciwnym wypadku zwraca zero.

Jednokrotne wykonanie Wykład 1 p. 46/52 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;

Jednokrotna inicjalizacja - przykład (I) Wykład 1 p. 47/52 #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;

Wykład 1 p. 48/52 Jednokrotna inicjalizacja - przykład (II) int main() pthread_t thread[3]; for (int i = 0; i < 3; i++) if (pthread_create(thread + i, NULL, Thread, NULL)) exit(1); for (int i = 0; i < 3; i++) pthread_join(thread + i, NULL); return 0; Wynik działania programu: Thread - 1026 Inicjalizacja zostala wykonana przez watek o identyfikatorze 1026 Thread - 2051 Thread - 3074

Wykład 1 p. 49/52 Jednokrotna inicjalizacja - pętla 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);...

Wykład 1 p. 50/52 Bramki 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).

Bramki - przykładowa implementacja (I) 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 ; 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; Wykład 1 p. 51/52

Bramki - przykładowa implementacja (II) 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); Wykład 1 p. 52/52 inline void pthread_barrier_destroy(pthread_barrier_t* barrier) pthread_mutex_destroy(&barrier->mutex); pthread_cond_destroy(&barrier->cond);