Automatyka i Robotyka Systemy czasu rzeczywistego Wykład 4.

Slides:



Advertisements
Podobne prezentacje
Język C/C++ Funkcje.
Advertisements

Podstawowe pojęcia programowania współbieżnego
Programowanie wielowątkowe
Mechanizmy pracy równoległej
Programowanie obiektowe
Programowanie obiektowe
Język ANSI C Funkcje Wykład: Programowanie komputerów
Systemy rozproszone W. Bartkiewicz
Języki programowania C++
Semafory Autorzy : Michał Winciorek Łukasz Jackowicz.
Budowa Sewera i Klienta. Funkcja Connect (1) Funkcja Connect (2)
argumenty wiersza poleceń: getopt
formatowanie kodu źródłowego
Nguyen Hung Son Uniwersytet Warszawski
Tablice.
Wprowadzenie do SystemC
Wykład nr 7: Synchronizacja procesów
Systemy operacyjne Wykład nr 5: Wątki Piotr Bilski.
Systemy operacyjne Wykład nr 4: Procesy Piotr Bilski.
1 Dygresja: cztery płyty główne…. 2 Dygresja: osobliwości C /* cos o nieistniejacym typie Boolean */ /* oraz o operatorze przecinkowym */ #include int.
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Podstawy programowania PP – WYK3 Wojciech Pieprzyca.
Podstawy programowania PP – LAB4 Wojciech Pieprzyca.
Instytut Fizyki Teoretycznej
Język ANSI C Operacje we/wy
Język Java Wielowątkowość.
15. MECHANIZMY SYNCHRONIZACJI WĄTKÓW Większość koncepcji stworzonych na potrzeby synchronizacji procesów ciężkich została zastosowana też do synchronizacji.
Semafory według normy POSIX
14. WĄTKI Procesy w tradycyjnym sensie (tworzone przez wykonanie funkcji fork) mają przydzielaną oddzielną przestrzeń adresową. W przestrzeni tej jest.
9. KOORDYNACJA PROCESÓW WSPÓŁBIEŻNYCH PRZY UŻYCIU INTERPRETATORA
Wątki.
Programowanie obiektowe W2
Diagramy czynności.
Podstawy programowania II
Podstawy programowania II Wykład 2: Biblioteka stdio.h Zachodniopomorska Szkoła Biznesu.
PROGRAMOWANIE SYSTEMOWE [2/3]
Podstawy programowania
Zbiór do posortowania mieści się w pamięci
Podstawy programowania. Język C i C++– podstawy Temat: 1
Informatyka I - Wykład ANSI C
Systemy operacyjne.
Przekazywanie argumentów
Podstawy programowania
Programowanie strukturalne i obiektowe
Podstawy programowania w języku C i C++
Jerzy F. Kotowski1 Informatyka I Wykład 14 DEKLARATORY.
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Problem sekcji krytycznej
Koncepcja procesu Zadanie i proces. Definicja procesu Process – to program w trakcie wykonywania; wykonanie procesu musi przebiegać w sposób sekwencyjny.
Przekazywanie parametrów do funkcji oraz zmienne globalne i lokalne
Wykład 7 Synchronizacja procesów i wątków
W ą t e k (lekki proces) thread.
Diagram aktywności (czynności)
K URS JĘZYKA C++ – WYKŁAD 1 ( ) Łagodne wprowadzenie do języka C++
Diagram czynności Diagram czynności (activity diagram) służy do modelowania dynamicznych aspektów systemu. Diagram czynności przedstawia sekwencyjne lub.
1 dynamiczny przydział pamięci malloc() free() realloc() calloc() memset() memcpy( ) mempcpy( ) memmove() (wskaźniki!! )
Programowanie proceduralne Podstawy Programowania dla geoinformatyków Wykład 3 Rafał Witkowski, 2015.
Procesy, wątki Program a proces Proces: Przestrzeń adresowa, kod, dane, stos (część pamięci do przechowania zmiennych lokalnych i niektórych adresów) Otwarte.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Wykład 2 Programowanie obiektowe. Programowanie obiektowe wymaga dobrego zrozumienia działania funkcji definiowanych przez użytkownika, w ten sposób będziemy.
Seminarium Dyplomowe: Metodyka i Techniki Programowania Autor: Bartłomiej Fornal.
Podstawy informatyki Preprocesor Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Wstęp do programowania Wykład 7
1 Opisy funkcji Adres strony WWW : html (należy odszukać hyperlink Function Index) (
Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka Podstawy.
Podstawy informatyki Mechanizm obsługi sytuacji wyjątkowych Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Wskaźniki Elżbieta Labocha.
Tworzenie wątków w Javie
Zapis prezentacji:

Automatyka i Robotyka Systemy czasu rzeczywistego Wykład 4

Wątki Mechanizm wątków to sposób realizacji obliczeń współbieżnych Wątek - wykonywanie pewnej sekwencji instrukcji Dla systemu wątek jest obiektem - (osobną strukturą danych) Każdy wątek jest "zarejestrowany" w systemie Dla programisty wątek to procedura w programie wykonywana współbieżnie z inną.

.. a zatem Program współbieżny składa się z dwóch lub więcej podzadań (procesów, wątków) – wykonywanych sekwencyjnie, lecz ich instrukcje wykonawcze wzajemnie się przeplatają w czasie (mogą być też wykonywane w pełni równolegle np.. na maszynach wieloprocesorowych) Nie czynimy żadnych założeń o kolejności przeplotów – poza strzeżonymi fragmentami – tzw. sekcjami krytycznymi

Wykorzystanie praktyczne - dowolne problemy dla maszyn wieloprocesorowych – celem jest skrócenie czasu obliczeń -specjalne algorytmy – np. sortowanie przez podział zbiorów sortowanych -konieczność działań równoległych – np. programy wymagające równoczesnej kontroli wielu napływających sygnałów z otoczenia i ich przetwarzania

Sortowanie Dla zbioru N-licznego potrzeba dla posortowania N(N-1)/2 porównań NN(N-1)/ ~ Jeśli podzielimy na 2 podzbiory N/2N/2(N/2-1)/2 500~ ~ scalenie dwóch zbiorów RAZEM a więc znaczny zysk – nawet gdybyśmy wykonywali w jednym procesie sekwencyjnie

W wielowątkowych programach współbieżnych łatwo o błędy Trzeba wyraźnie określić, które czynności mają być wykonywane równolegle Nie wolno np. rozpocząć scalania, dopóki nie zakończą pracę wątki składowe sortujące

Po uruchomieniu programu powstaje: proces - rezerwacja zasobów jeden wątek – rozpoczęcie wykonywania procedury głównej. W ramach jednego procesu może działać jeden lub więcej wątków. Kolejne wątki mogą być utworzone w trakcie pracy programu. Wątki utworzone przez proces stają się automatycznie jego "własnością", nie "żyją" dłużej niż ich właściciel Realizacja programowa

Elementy składowe zadania wykonywane współbieżnie z innymi A B C A B C współbieżnie sekwencyjnie przeplot instrukcji w czasie

Serwer cały czas nasłuchuje przychodzących połączeń (wątek główny). W chwili pojawienia się żądania połączenia przez klienta, tworzony jest nowy wątek, który zajmuje się jego obsługą. Wątek główny nadal nasłuchuje… Gdy wielu klientów – wiele wątków ich obsługi Inny przykład, o którym mówiliśmy wcześniej: Serwer HTTP

Nasłuchuj Utwórz HTML Wyślij HTML Utwórz HTML Wyślij HTML Wątek głównyWątek 2Wątek 3 Uruchamianie wątków kopii – wykonujących tę samą funkcję – z innymi argumentami

Każdy wątek w systemie posiada swój unikalny identyfikator. Standard POSIX definiuje specjalny typ danych pthread_t do reprezentacji identyfikatora wątku. Przy pomocy identyfikatora można wskazać na dowolny wątek w systemie. Do pobrania identyfikatora wątku można użyć procedury pthread_self() Możliwe jest również porównywanie dwu identyfikatorów funkcją pthread_equal(). Identyfikator wątku Korzystanie z mechanizmu obsługi wątków: plik nagłówkowy pthread.h

#include int main(int argc, char * argv[]) { pthread_t id; id = pthread_self(); printf("%u\n",id); return 0; } wypisanie identyfikatora wątku głównego

pthread_create(&s_id, &attr, funkcja, void* arg) gdzie: s_id - NULL, lub wskaźnik do obiektu typu pthread_t, attr – wskaźnik do struktury opisującej atrybuty tworzonego wątku, funkcja – nazwa procedury dla realizacji wątku, arg - argument przekazany do funkcji. Tworzenie wątku Funkcja pthread_create() o składni:

#include void* drugi(void* arg) { /* Procedura wykonywana przez watek */ pthread_t id; id = pthread_self(); printf("Drugi: %u\n",id); return NULL; } int main(int argc, char* argv[]) { pthread_t id; /* Identyfikator tego watku*/ pthread_t drugi_id; /* identyfikator tworzonego watku */ pthread_attr_t attr; /* Atrybuty watku */ /* Inicjalizuje strukture z atrybutami*/ pthread_attr_init( &attr ); /* Utworzenie watku - "drugi" to nazwa funkcji, ktora bedzie watkiem - funkcja drugi()*/ pthread_create(&drugi_id, &attr, drugi, NULL); /* Wyswietl identyfikator */ id = pthread_self(); printf("Glówny: %u\n", id); /* Czekaj na zakonczenie watku*/ pthread_join(drugi_id, NULL); return 0; }

#include void* drugi(void* arg) { pthread_t id; pthread_t main_id; id = pthread_self(); main_id = (int) arg; printf("Drugi: %u\n",id); printf("A to id ojca: %u\n", main_id); return NULL; } int main(){ pthread_t id; /* Identyfikator tego watku*/ pthread_t drugi_id; /* identyfikator tworzonego watku */ pthread_attr_t attr; /* Atrybuty watku */ pthread_attr_init( &attr ); /* Utworz nowy watek i przekaz 'id' jako argument */ pthread_create(&drugi_id, &attr, drugi, (void*) id); /* Czekaj na zakonczenie watku "drugi" */ printf("id drugiego: %u\n",drugi_id); return 0; } Przekazywanie argumentu liczbowego do wątku poprzez argument arg Pierwszy: 1 Drugi: 2 A to id ojca: 1 id drugiego: 2 tu: przekazanie id wątku głównego

#include void* drugi(void* arg) { pthread_t id; printf("Argument: %s\n",arg); id = pthread_self(); printf("Drugi: %u\n",id); return NULL; } int main(){ pthread_t id; /* Identyfikator tego watku*/ pthread_t drugi_id; /* identyfikator tworzonego watku */ pthread_attr_t attr; /* Atrybuty watku */ pthread_attr_init( &attr ); /* Utworz nowy watek i przekaz 'tekst' jako argument */ char *tekst = "Jakis tam tekst"; printf("%c\n", tekst[0]);//wypisze J pthread_create(&drugi_id, &attr, drugi, (void*) tekst); /* Czekaj na zakonczenie watku "drugi" */ printf("id drugiego: %u\n",drugi_id); return 0; } Przekazywanie argumentu tekstowego do wątku poprzez argument arg. J Argument: Jakis tam tekst Drugi: 2 id drugiego: 2 tu: przekazanie id wątku głównego

return NULL; lub pthread_exit(NULL); Zakończenie wątku

Funkcją pthread_join() pthread_join(id,&retval) powoduje wstrzymanie programu (wątku macierzystego) aż do momentu zakończenia wątku posiadającego id. Dołączanie wątku (join) Wymagana często jego obsługa, bo co będzie jeśli wątek główny zakończy swoje działanie a potomny nadal będzie musiał działać?

void* drugi(void* arg) { int i; for(i=0;i<4;i++) { printf("Drugi i: %d\n",i); sleep(1); } return NULL; } Dłuższe działanie procedury obsługi wątku … pthread_create(&drugi_id, &attr, drugi, "10"); pthread_join(drugi_id, &retval); printf("Koniec \n"); return 0; } Drugi i: 0 Drugi i: 1 Drugi i: 2 Drugi i: 3 Koniec Drugi i: 0 Koniec … pthread_create(&drugi_id, &attr, drugi, "10"); printf("Koniec \n"); return 0; bez join niedokończony wątek

void* drugi(void* arg) { int i; for(i=0;i<4;i++) { printf("Drugi i: %d\n",i); sleep(1); } return NULL; } Dłuższe działanie procedury obsługi wątku pthread_create (&drugi_id, &attr, drugi, "10"); printf("AKCJA 1\n"); pthread_join(drugi_id, NULL); printf("AKCJA 2\n"); printf("AKCJA 3\n"); return 0; Drugi i: 0 AKCJA 1 Drugi i: 1 Drugi i: 2 Drugi i: 3 AKCJA 2 AKCJA 3 Drugi i: 0 AKCJA 1 AKCJA 2 Drugi i: 1 Drugi i: 2 Drugi i: 3 AKCJA 3 pthread_create (&drugi_id, &attr, drugi, "10"); printf("AKCJA 1\n"); printf("AKCJA 2\n"); pthread_join(drugi_id, NULL); printf("AKCJA 3\n"); return 0; WYBÓR MIEJSCA DOŁĄCZENIA

Wątek można odłączyć. Po zakończeniu wątku pewne jego zasoby są wciąż przechowywane, aż do momentu dołączenia wątku funkcją pthread_join(). Wątek odłączony zwalnia swoje zasoby zaraz po zakończeniu pracy. Nie ma potrzeby (ani możliwości) oczekiwania (join) na odłączony wątek. Wszelka informacja związana z wątkiem znika w chwili zakończenia jego pracy. Wątek odłącza się funkcją pthread_detach(): pthread_detach(id) Odłączanie wątku (detach)

void* drugi(void* arg) { printf("Drugi\n"); return NULL; } Procedura obsługi wątku pthread_create(&drugi_id, &attr, drugi, NULL); int i; for(i=0;i<4;i++) { printf("Glowny i: %d\n",i); sleep(1); } printf("drugi_id:%d\n",drugi_id); pthread_detach(drugi_id); printf("AKCJA \n"); pthread_create(&drugi_id2, &attr,drugi,NULL ); printf("drugi_id2:%d\n",drugi_id2); Drugi Glowny i: 0 Glowny i: 1 Glowny i: 2 Glowny i: 3 drugi_id:2 AKCJA Drugi drugi_id2:2 Drugi Glowny i: 0 Glowny i: 1 Glowny i: 2 Glowny i: 3 drugi_id:2 AKCJA Drugi drugi_id2:3 pthread_create(&drugi_id, &attr, drugi, NULL); int i; for(i=0;i<4;i++) { printf("Glowny i: %d\n",i); sleep(1); } printf("drugi_id:%d\n",drugi_id); printf("AKCJA \n"); pthread_create(&drugi_id2, &attr, drugi, NULL ); printf("drugi_id2:%d\n",drugi_id2); DETACH bez detach – mimo że wątek zakończył działanie to pamięta swoje id

Współbieżna praca dwóch wątków #include void* drugi(void* arg) { int i; pthread_t id; id = pthread_self(); for( i=0; i<10; i++) { printf("\t\t\tDrugi: %ld\n",(long int)id); sleep(1); } return NULL; } int main(int argc, char* argv[]) { int i; /* Zmienna licznikowa dla petli */ pthread_t id; /* Identyfikator tego watku*/ pthread_t drugi_id; /* identyfikator tworzonego watku */ pthread_attr_t attr; /* Atrybuty watku */ pthread_attr_init( &attr ); pthread_create(&drugi_id, &attr, drugi, NULL); id = pthread_self(); for( i=0; i<5; i++) { printf("Glowny: %ld\n",(long int)id); sleep(2); } pthread_join(drugi_id, NULL); return 0; } Drugi: 2 Glowny: 1 Drugi: 2 Glowny: 1 Drugi: 2 Glowny: 1 Drugi: 2 Glowny: 1 Drugi: 2 Glowny: 1 Drugi: 2

Problemy…. parallel slowdown Podczas wykonywania programu równoległego, poszczególne jego zadania składowe mogą operować na wspólnych zasobach Nie każda próba wykonania równoległego daje przyspieszenie obliczeń. Jeśli program jest dzielony na wiele podzadań, to w pewnym momencie problemy komunikacji zaczynają przeważać nad zyskiem ze "zrównoleglenia". Pomimo zwiększania teoretycznej mocy obliczeniowej może dojść do spowolnienia obliczeń. Zjawisko to nazywane jest spowolnieniem równoległym (ang. parallel slowdown).

Do poprawnej współpracy wątków często potrzebna jest synchronizacja ich pracy. W programowaniu wielowątkowym stosuje się w tym celu mechanizmy synchronizacji. Mechanizmy są używane w celu: Synchronizacja zapewnienia prawidłowych zależności czasowych przy współbieżnym wykonywaniu algorytmów, zapewnienia spójnego dostępu do danych.

…ponieważ… Np. podzadanie 1 ma N instrukcji, a podzadanie 2 ma M instrukcji. Zadania są wykonywane współbieżnie i kolejność czasowa wykonywania k-tej instrukcji zadania 1 i i-tej instrukcji zadania 2 może być przypadkowa – inna dla różnych wykonań programu (decydują o tym stany zasobów, sygnały zewnętrzne itp.) Musimy zatem zapewnić sytuację, że ZAWSZE wyniki będą PRAWIDŁOWE

Wątek może zmienić za wcześnie dane, które potrzebne są innemu wątkowi w stanie poprzednim Wątek może za późno obliczyć dane potrzebne innemu wątkowi Główne błędy przy braku synchronizacji

Wątek AWątek B Podstaw wartość x do Ndodaj 1 do N Podstaw wartość y do Mdodaj 1 do M Sprawdź, czy M jest większe lub równe N decydująca jest kolejność wykonywania instrukcji za wspólnych danych co może powodować błędy !

Brak synchronizacji oblicz B akcja Wątek główny Wątek drugi C=A+B oblicz A czas B nieznane

C= A+B A=1 B=1 Wątek główny Wątek drugi B=2 czas modyfikacja B Problem pojawia się przy dostępie do wspólnych danych, w momencie gdy dwa wątki próbują modyfikować dane "jednocześnie". Nieprzewidywalne rezultaty (nieprawidłowy wynik obliczeń). Race condition Wyścig Wyścigi i wzajemne wykluczanie Konstrukcje w aplikacji współbieżnej powodujące, że wynik aplikacji w sposób przypadkowy zależy od czasu wykonania pewnych ciągów instrukcji Wykluczanie – sytuacja, gdy dwa podzadania (ich fragmenty) nie mogą być wykonywane równocześnie

#include #define ILE_WATKOW 8 #define LIMIT pthread_t tid[ILE_WATKOW]; static int x; void * kod (void *arg) { int numer=(int)arg; if (numer%2==0) { while (x<LIMIT) x++; } else { while (x>0) x--; } printf("Na mecie: %d x: %d \n", numer, x); return (void*) numer; } int main (int argc, char *argv[]) { int i, status, num; num = LIMIT/2; // for (i=0; i< ILE_WATKOW; i++) pthread_create (&tid[i], NULL, kod, (void *)(i+1)); for (i=0; i< ILE_WATKOW; i++) pthread_join (tid[i], NULL); printf("KONIEC !!! x: %d\n",x); return (0); } Na mecie: 1 x: 0 Na mecie: 2 x: Na mecie: 3 x: 0 Na mecie: 4 x: Na mecie: 5 x: 0 Na mecie: 6 x: Na mecie: 7 x: 0 Na mecie: 8 x: KONIEC !!! x: wątków "na wyścigi" zwiększa w pętli lub zmniejsza liczbę (zależy od numeru wątku – parzysty/nieparzysty)

… chroniona zmienna, która ustanawia metodę kontroli dostępu przez wiele procesów/wątków do wspólnego zasobu Semafory po raz pierwszy opisane przez Edsgera Dijkstrę Semafor Semafory binarne i zliczające Semafory zliczające – problem stolików w restauracji liczba_stołów liczba_wolnych po zajęciu miejsca (jeśli liczba_wolnych>0) liczba_wolnych - - po zwolnieniu stołu liczba_wolnych++ liczba_wolnych=liczba_stołów i brak chętnych - oczekiwanie lub koniec WYKLUCZANIE – nie można posadzić dwóch osób na tym samym miejscu!

Mutex (Mutual Exclusion) jest mechanizmem synchronizacji, który umożliwia zagwarantowanie wyłączności w dostępie do danych. Stosując mutex można zabezpieczyć się przed problemem race condition. Mutex jest obiektem, który może być w jednym z dwu stanów: odblokowany (unlocked) zablokowany (locked) Dwie podstawowe operacje, które są przeprowadzane na muteksach to: blokowanie (lock) odblokowywanie (unlock) Mutex to szczególny przypadek semaforów binarnego i ogólnego

… to wymaganie, aby ciąg operacji na zasobie (pamięci) był wykonany w trybie wyłącznym – tylko przez jeden z wątków (procesów) Wzajemne wykluczanie

Podzadanie APodzadanie B 1A: Zablokuj zmienną V1B: Zablokuj zmienną V 2A: Odczytaj zmienną V2B: Odczytaj zmienną V 3A: Dodaj 1 do zmiennej V3B: Dodaj 3 do zmiennej V 4A: Zapisz wartość w zmiennej V4B: Zapisz wartość w zmiennej V 5A: Odblokuj zmienną V5B: Odblokuj zmienną V Tylko jedno z dwóch zadań z sukcesem zablokuje zmienną V i uzyska do niej wyłączny dostęp, podczas gdy drugie będzie musiało czekać na jej odblokowanie. Zastosowanie powyższej konstrukcji daje gwarancję poprawnego wykonania programu, kosztem jest jednak jego spowolnienie, które może być znaczne.

Blokuj MUTEX Odblokuj MUTEX B=1 C=A+B Sekcja krytyczna

założyć, że na odcinku drogi może przebywać jednocześnie nieokreślona liczba pojazdów (zależąca od ich prędkości) Semafory i muteksy Implementacja: Stan świateł:

Semafory są obiektami globalnymi. Dowolny proces może je "opuszczać" albo "podnosić". Umożliwia to powstanie sytuacji, w której jedno z zadań wykona operację CZEKAJ aby synchronizować dostęp do jakiegoś zasobu, a później inne, niezwiązane logicznie z tym zasobem, podniesie semafor. Może to prowadzić do uszkodzenia wspólnych danych, a nawet do załamania całego systemu. Dlatego też, wiele implementacji wprowadza pewne cechy dla muteksów. Jedną z nich jest zasada posiadania. Otóż polega ona na tym, że jeśli jakieś zadanie zablokuje muteks (nada mu wartość 1), to tylko ono może ten muteks odblokować (nadać mu wartość 0). Takie podejście eliminuje potencjalny problem niespójności danych.

Blokowanie wielu zmiennych przy użyciu nieatomowych blokad może spowodować zakleszczenie. Atomowość blokady to własność, która gwarantuje, że wszystkie zmienne blokowane są razem, to znaczy jeśli dwa podzadania próbują zablokować kilka zmiennych, to uda się to tylko jednemu z nich i blokada powstanie na wszystkich zmiennych. Jeśli natomiast blokady nie są atomowe, to może się zdarzyć, że jeśli dwa podzadania próbują zablokować te same dwie zmienne, to jedno z nich zablokuje jedną a drugie drugą. Wówczas oba podzadania czekają na siebie nawzajem i żaden z nich nie może zakończyć działania. Taką sytuację nazywamy zakleszczeniem. Zakleszczenie

Dane wspólne dla wątków powinny być modyfikowane tylko wewnątrz sekcji krytycznych. Wtedy wątek ma gwarancję, że inny wątek nie zmodyfikuje mu danych skojarzonych z muteksem, ma wyłączność w dostępie do danych. Typ pthread_mutex_t reprezentujący mutex oraz zestaw funkcji operujących na muteksie. Istotne funkcje: pthread_mutex_lock() - blokowanie muteksa. Jeśli mutex jest zablokowany przez inny wątek, to bieżący wątek jest wstrzymywany aż do momentu odblokowania. Jeśli mutex jest odblokowany, to bieżący wątek blokuje go. pthread_mutex_unlock() - odblokowanie (zwolnienie) muteksa. Synchronizacja muteksem

#include int b; /* Dane wspolne */ void* drugi (void* arg) { printf("\t\t\t\t2: Pracuje...\n"); sleep(1); /* Cos tam robie 1 sekunde */ printf("\t\t\t\t2: Modyfikuje b\n"); b = 2; printf("\t\t\t\t2: b = %d\n", b); return NULL; } int main(int argc, char* argv[]) { pthread_t drugi_id; /* identyfikator watku */ pthread_attr_t attr; /* Atrybuty watku */ int a,c; /* Dane lokalne watku glownego */ pthread_attr_init( &attr ); pthread_create(&drugi_id, &attr, drugi, NULL); printf("1:Modyfikuje b\n"); a = 1; b = 1; /* Inicjalizuj "a" i "b" */ printf("1: a = %d, b = %d\n",a, b); /* Cos tam robimy... */ printf("1: Pracuje... \n"); sleep(2); /* Oblicz "c" i wydrukuj wynik */ c = a + b; printf("1: c = a + b = %d\n",c); if(c == 2) { printf("1: Obliczenia prawidlowe.\n"); } else { printf("1: Zle!\n"); } /* Czekaj na zakonczenie watku "drugi" */ pthread_join(drugi_id, NULL); return 0; } 2: Pracuje... 1:Modyfikuje b 1: a = 1, b = 1 1: Pracuje... 2: Modyfikuje b 2: b = 2 1: c = a + b = 3 1: Zle! bez blokady

#include int b; /* Dane wspolne */ /* Mutex chroniacy dane wspolne */ pthread_mutex_t mutex_b = PTHREAD_MUTEX_INITIALIZER; /* Procedura wykonywana przez watek */ void* drugi (void* arg) { printf("\t\t\t\t2: Pracuje...\n"); sleep(1); /* Cos tam robie przez sekunde */ /*Blokuj mutex */ pthread_mutex_lock(&mutex_b); printf("\t\t\t\t2: Modyfikuje b\n"); b = 2; printf("\t\t\t\t2: b = %d\n", b); pthread_mutex_unlock(&mutex_b); /* Odblokuj*/ return NULL; } int main (int argc, char* argv[]) { pthread_t drugi_id; /* identyfikator tworzonego watku */ pthread_attr_t attr; /* Atrybuty watku */ int a,c; /* Dane lokalne watku glownego */ pthread_attr_init( &attr ); pthread_create(&drugi_id, &attr, drugi, NULL); /* Inicjalizuj "a" */ printf("1:Modyfikuje b\n"); a = 1; pthread_mutex_lock(&mutex_b); /* Blokuj mutex */ b = 1; printf("1: a = %d, b = %d\n",a, b); printf("1: Pracuje... \n"); /* Cos tam robimy... */ sleep(2); c = a + b; /* Oblicz "c" */ pthread_mutex_unlock(&mutex_b); /* Odblokuj mutex */ printf("1: c = a + b = %d\n",c); /* Drukuj wynik */ if(c == 2) { printf("1: Obliczenia przeprowadzone prawidlowo.\n"); } else { printf("1: Zle!!!!\n"); } /* Czekaj na zakonczenie watku */ pthread_join(drugi_id, NULL); return 0; } 2: Pracuje... 1:Modyfikuje b 1: a = 1, b = 1 1: Pracuje... 1: c = a + b = 2 1: Obliczenia przeprowadzone prawidlowo. 2: Modyfikuje b 2: b = 2 Prawidłowo z muteksem