Muteksy

11
Muteksy Muteksy (mutex – MUTual EXclusion) są prostymi obiektami synchronizacyjnymi pełniącymi rolę semaforów binarnych dla wątków (chroniącymi sekcje krytyczne programów). W odróżnieniu od semaforów w pakiecie IPC występują jedynie pojedynczo (nie tworzą tablic, na których można wykonywać niepodzielne operacje). Interpretacja ich wartości jest odwrotna: 0 – muteks otwarty, wartość dodatnia – muteks zamknięty. W systemach linuksowych występują trzy rodzaje muteksów: szybkie (fast), sprawdzające (error checking) i rekurencyjne (recursive). Domyślne atrybuty muteksu (ustawiane przez stałą PTHREAD_MUTEX_INITIALIZER) to (szybki, otwarty). Muteks szybki jest najprostszy, gdyż pamięta tylko swój stan (otwarty / zamknięty), a nie pamięta, kto

description

Muteksy Muteksy ( mutex – MUTual EXclusion ) są prostymi obiektami synchronizacyjnymi pełniącymi rolę semaforów binarnych dla wątków (chroniącymi sekcje krytyczne programów). W odróżnieniu od semaforów w pakiecie IPC występują jedynie pojedynczo (nie tworzą tablic, na których można - PowerPoint PPT Presentation

Transcript of Muteksy

Page 1: Muteksy

Muteksy

Muteksy (mutex – MUTual EXclusion) są prostymi obiektami synchronizacyjnymi pełniącymi rolę

semaforów binarnych dla wątków (chroniącymi sekcje krytyczne programów). W odróżnieniu od

semaforów w pakiecie IPC występują jedynie pojedynczo (nie tworzą tablic, na których można

wykonywać niepodzielne operacje). Interpretacja ich wartości jest odwrotna: 0 – muteks otwarty,

wartość dodatnia – muteks zamknięty.

W systemach linuksowych występują trzy rodzaje muteksów: szybkie (fast), sprawdzające (error

checking) i rekurencyjne (recursive). Domyślne atrybuty muteksu (ustawiane przez stałą

PTHREAD_MUTEX_INITIALIZER) to (szybki, otwarty).

Muteks szybki jest najprostszy, gdyż pamięta tylko swój stan (otwarty / zamknięty), a nie pamięta, kto

(który wątek) go zamknął. Z tego powodu może stać się przyczyną blokady wątku, który będzie

próbował zamknąć go po raz drugi. Teoretycznie uwolnić wątek z takiej blokady może inny wątek,

wywołując funkcję otwierającą muteks (ale wystąpienie takiej sytuacji świadczy prawdopodobnie

o błędach logicznych w programie).

Page 2: Muteksy

Muteks sprawdzający jest semaforem binarnym pamiętającym, kto go zamknął (wątek ten staje się

właścicielem muteksu na czas jego zamknięcia). Może w związku z tym zapobiegać błędom:

- nie pozwala drugi raz zamknąć się temu samemu wątkowi (właścicielowi);

- nie pozwala otworzyć się wątkowi niebędącemu jego właścicielem;

- próba otwarcia, jeśli już był otwarty, powoduje sygnalizację błędu.

Muteks rekurencyjny jest „zamkiem zamykanym na wiele spustów” – posiada licznik operacji

zamknięcia (przez właściciela) i aby go otworzyć, potrzeba tyle samo operacji otwarcia (przez

właściciela).

Uwaga

Maksymalna liczba zamknięć muteksu rekurencyjnego jest zależna od implementacji. Dokumentacja

w systemie Linux ani jej nie specyfikuje, ani nie podaje, jaki może być skutek próby przekroczenia.

Page 3: Muteksy

int pthread_mutex_init (pthread_mutex_t *muteks, const pthread_mutexattr_t *atrybuty);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu (jest to możliwe tylko wtedy, gdy muteks jest tworzony

dynamicznie, a nie statycznie przez kompilator)

muteks – zwracany wskaźnik na zainicjowany muteks

atrybuty – wskaźnik na obiekt atrybutów (mający zainicjować muteks)

Działanie: tworzy muteks o danych atrybutach.

int pthread_mutex_lock (pthread_mutex_t *muteks);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

muteks – wskaźnik na (zainicjowany) muteks

Page 4: Muteksy

Działanie: zamyka dany muteks, jeśli był otwarty, i przyporządkowuje mu właściciela, jeśli muteks nie

jest muteksem szybkim. Jeśli muteks już był zamknięty, a zamknąć go próbował wątek

niebędący jego właścicielem, zawiesza dany wątek aż do otwarcia muteksu przez

właściciela. Jeśli próbował zamknąć go ponownie właściciel:

- blokada wątku w przypadku muteksu szybkiego (chyba, że inny wątek go uwolni);

- błąd w przypadku muteksu sprawdzającego;

- zwiększenie licznika zamknięć w przypadku muteksu rekurencyjnego.

int pthread_mutex_trylock (pthread_mutex_t *muteks);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

muteks – wskaźnik na muteks

Działanie: takie samo, jak pthread_mutex_lock ( ), ale zamiast zawieszać wątek próbujący zamknąć

zamknięty przez inny wątek (lub ten sam, w przypadku szybkiego) muteks, zwraca błąd.

Page 5: Muteksy

int pthread_mutex_unlock (pthread_mutex_t muteks);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

muteks – wskaźnik na muteks

Działanie: otwiera dany muteks. Dokładniej: jeśli pod muteksem czekały jakieś wątki, jeden z nich

zostaje uwolniony i przejmuje muteks na własność zamykając go ponownie (należy

przyjąć, że wybór jest losowy). Jeśli żaden wątek nie czekał, muteks pozostaje otwarty

i bez właściciela.

W przypadku muteksu sprawdzającego otwarcie dochodzi do skutku tylko w przypadku

wątku będącego właścicielem (dla innych wątków zwracany jest błąd).

W przypadku muteksu rekurencyjnego licznik zamknięć zostaje zmniejszony o 1 (jeśli

osiągnął wartość 0 i żaden wątek nie czekał, muteks pozostaje otwarty i bez właściciela).

Page 6: Muteksy

int pthread_mutex_destroy (pthread_mutex_t muteks);

Zwraca: 0 w przypadku błędu

niezerowy kod w przypadku błędu

muteks – wskaźnik na muteks

Działanie: jeśli muteks był utworzony dynamicznie i jest otwarty, funkcja powinna zlikwidować go

i zwrócić do systemu zajmowane przez niego zasoby. Jeśli dynamiczne tworzenie nie

jest zaimplementowane (muteks jest tworzony statycznie przez kompilator), funkcja

jedynie sprawdza, czy muteks jest otwarty (i zwraca błąd, jeśli nie jest).

Page 7: Muteksy

Zmienne warunkowe

Zmienne warunkowe (condition variable) są mechanizmami synchronizacji zaprojektowanymi do

współpracy z muteksami w sytuacjach, gdy użycie pojedynczych muteksów nie jest wystarczające.

Ich głównym przeznaczeniem jest blokowanie wątków do czasu, aż pewien warunek logiczny

zostanie spełniony (stąd ich nazwa). Jednym z typowych zastosowań jest rozwiązywanie problemu

producenta i konsumenta. Zmienna warunkowa musi być wykorzystywana łącznie z muteksem –

sama nie ma racji bytu.

Podobnie, jak dla przypadku muteksów, standard POSIX przewiduje możliwość dynamicznego

tworzenia i likwidacji zmiennych warunkowych w programie. Jeśli nie jest to zaimplementowane,

zmienne warunkowe są tworzone statycznie przez kompilator.

Działanie zmiennych warunkowych jest dość skomplikowane i trudne do zrozumienia (jak również

do modelowania przy użyciu diagramów stanów i przejść). Zalecane jest zapoznanie się

z przykładem umieszczonym w opisie (manualu) funkcji obsługujących zmienne warunkowe.

Page 8: Muteksy

int pthread_cond_init (pthread_cond_t *zmienna, pthread_condattr_t *atrybuty);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu (jest to możliwe tylko wtedy, gdy zmienna jest tworzona

dynamicznie, a nie statycznie przez kompilator)

zmienna – zwracany wskaźnik na zainicjowaną zmienną

atrybuty – wskaźnik na obiekt atrybutów

Działanie: tworzy zmienną warunkową o danych atrybutach.

int pthread_cond_wait (pthread_cond_t *zmienna, pthread_mutex_t *muteks);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

zmienna – wskaźnik na (zainicjowaną) zmienną warunkową

Page 9: Muteksy

muteks – wskaźnik na muteks (który powinien być wcześniej zamknięty przez ten wątek)

Działanie: wykonuje niepodzielnie dwie czynności: otwiera dany muteks i zawiesza wątek pod daną

zmienną warunkową. Aby program działał poprawnie, wątek musi wcześniej wywołać

wywołać funkcję zamykającą ten muteks. Powrót z omawianej funkcji następuje po

(niedeterministycznym) uruchomieniu wątku i powoduje automatycznie ponowne

zamknięcie danego muteksu.

int pthread_cond_timedwait (pthread_cond_t *zmienna, pthread_mutex_t *muteks,

const struct timespec *czas);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

zmienna – wskaźnik na zmienną warunkową

muteks – wskaźnik na muteks

czas – wskaźnik na strukturę określającą maksymalny czas oczekiwania

Page 10: Muteksy

Działanie: takie samo, jak działanie funkcji pthread_cond_wait ( ), dopóki nie zostanie przekroczony

dany limit czasu, zaś po jego przekroczeniu (z powodu braku obudzenia przez inny wątek)

wątek zostaje ponownie uruchomiony, muteks zamknięty, a funkcja zwraca kod błędu.

int pthread_cond_signal (pthread_cond_t *zmienna);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

zmienna – wskaźnik na zmienną warunkową

Działanie: uruchamia jeden z wątków (niedeterministycznie wybrany) czekających pod daną zmienną

warunkową (jeśli żaden wątek nie czeka, funkcja nic nie robi).

int pthread_cond_broadcast (pthread_cond_t *zmienna);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

Page 11: Muteksy

zmienna – wskaźnik na zmienną warunkową

Działanie: uruchamia wszystkie wątki czekające pod daną zmienną warunkową (jeśli żaden wątek nie

czeka, funkcja nic nie robi).

int pthread_cond_destroy (pthread_cond_t *zmienna);

Zwraca: 0 w przypadku sukcesu

niezerowy kod w przypadku błędu

zmienna – wskaźnik na zmienną warunkową

Działanie: podobnie, jak w przypadku muteksów, jeśli pod zmienną nie czeka żaden wątek, likwiduje

ją i zwraca do systemu zajmowane zasoby (jeśli zmienna była utworzona dynamicznie).

Jeśli zmienna była utworzona statycznie, sprawdza jedynie, czy nie czeka pod nią żaden

wątek.