25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
Operační systémy Tomáš Hudec 7 Prostředky programovacích jazyků pro IPC Obsah: 7.1
Monitor, 7.1.1 Použití monitoru pro řízení přístupu do kritické sekce, 7.1.2 Použití monitoru pro synchronizaci, 7.1.3 Producenti a konzumenti – řešení pomocí monitoru,
7.2
Bariéra, 7.2.1 Bariéra v posixových vláknech,
7.3 7.4
Podmínková proměnná, Opakování.
Řada programovacích jazyků nabízí prostředky pro řešení meziprocesové komunikace jako je synchronizace a řízení přístupu do kritické sekce.
7.1 Monitor Monitor je nástrojem pro řešení vzájemného vylučování a synchronizace. Koncept monitoru vynalezl již v roce 1972 Per Brinch Hansen. O dva roky později koncept podmínkových front monitoru vylepšil Tony Hoare (plným jménem sir Charles Antony Richard Hoare). Jedná se konstrukci programovacího jazyka velmi podobnou třídě. Všechny lokální proměnné jsou přístupné pouze pomocí funkcí monitoru. Nejdůležitější vlastností monitoru je, že uvnitř něj smí být v každém okamžiku nejvýše jedno vlákno (proces). Tím je zaručeno vzájemné vylučování. Synchronizaci lze řešit pomocí podmínkových proměnných monitoru. S každou podmínkovou proměnnou je sdružena fronta pro vlákna čekající na danou podmínku. Nad podmínkovými proměnnými jsou implementovány operace condition_wait a condition_signal. Operace condition_wait zablokuje vlákno a zařadí je do příslušné fronty (dle podmínkové proměnné). Vlákno může být probuzeno operací condition_signal na příslušné podmínkové proměnné.
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
1/6
25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
Monitor
7.1.1 Použití monitoru pro řízení přístupu do kritické sekce Jelikož monitor zaručuje vzájemné vylučování při spouštění svých funkcí, stačí deklarovat sdílená data v monitoru a umístit kritickou sekci do jeho funkce. řešení monitor CS { // deklarace sdílených proměnných critical_section() {
kritická sekce // kód kritické sekce
řešení } }
Kód vláken: repeat
řešení
CS.critical_section(); // kritická sekce // zbytková sekce forever
7.1.2 Použití monitoru pro synchronizaci Předpokládejme, že jedno vlákno má provést akci (vypočítat hodnotu sdílené proměnné), na kterou musí jiné vlákno počkat (použití vypočtené hodnoty). Pro synchronizaci lze použít podmínkové proměnné monitoru v kombinaci s proměnnou vypovídající o stavu dokončení akce.
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
2/6
25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
řešení monitor sync { bool done = false; // proměnná určující stav akce cond_t condition;
// deklarace podmínkové proměnné
finished() {
// zavolá se po vykonání akce
done = true; condition_signal(condition); } await() { // zavolá se při čekání na dokončení akce if (!done) condition_wait(condition); } }
Kód vlákna provádějícího akci, zde vypočtení hodnoty sdílené proměnné x: x = calculate();
// provedení akce
sync.finished();
// signalizace dokončení akce
synchronizace – signalizace
Kód vlákna čekajícího na dokončení akce: synchronizace – čekání sync.await(); use(x);
// pokud akce nebyla ještě provedena, bude čekat // použití hodnoty sdílené proměnné x vypočtené jiným vláknem
7.1.3 Producenti a konzumenti – řešení pomocí monitoru Definice problému – vizte předchozí kapitolu. Stačí definovat sdílená data uvnitř monitoru (monitor zajistí vzájemné vylučování) a pro synchronizaci použít podmínkové proměnné. Funkce pro vložení a výběr položek budou součástí monitoru.
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
3/6
25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
řešení monitor PC { buffer[n];
// sklad: pole o kapacitě n položek
in = 0;
// index následující volné pozice (pro uložení producentem)
out = 0;
// index následující obsazené pozice (pro vyzvednutí konzumentem)
count = 0;
// počet položek ve skladě
cond_t not_full;
// signalizace volného místa ve skladě
cond_t not_empty;
// signalizace neprázdného skladu
void append(item) {
// vkládání do skladu
if (count == n)
synchronizace – čekání
// je-li sklad plný,
condition_wait(not_full);
// čekání na uvolnění místa
kritická sekce buffer[in] = item;
// uložení položky do skladu na pozici in
in = (in + 1) % n; count++;
// posunutí indexu na následující místo // zvýšení počtu uložených položek
synchronizace – signalizace condition_signal(not_empty);
// signalizace neprázdného skladu
} void take(item_t *item) {
// vybírání ze skladu
if (count == 0)
synchronizace – čekání
// je-li sklad prázdný
condition_wait(not_empty); // čekání na vložení položky
kritická sekce *item = buffer[out];
// vyzvednutí položky ze skladu na pozici out
out = (out + 1) % n; count--;
// posunutí indexu na následující místo // snížení počtu uložených položek
synchronizace – signalizace condition_signal(not_full);
// signalizace volného místa ve skladě
} }
Vlákno producenta: repeat item = produce();
// vyprodukování položky
PC.append(item);
// vložení položky do skladu
řešení
forever
Vlákno konzumenta: repeat PC.take(&item); consume(item); forever
řešení // vyzvednutí položky ze skladu // zpracování položky
Vzájemné vylučování je zaručeno, neboť manipulace se sdílenými daty probíhá výhradně v monitoru.
7.2 Bariéra
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
4/6
25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
Bariéra je speciální proměnná, pomocí které lze synchronizovat skupinu vláken. Jakmile vlákno dorazí k bariéře, bude zablokováno až do okamžiku, než k bariéře dorazí daný počet vláken. Deklarace a inicializace: deklarace / inicializace barrier_t barrier;
// deklarace bariéry
barrier_init(&barrier, 3); // stanovení počtu vláken k synchronizaci
Použití bariér v jednotlivých vláknech: synchronizace – čekání barrier_wait(&barrier);
// čekání na daný počet vláken
// nyní poběží vlákna souběžně
7.2.1 Bariéra v posixových vláknech Příklad knihovny, která podporuje bariéry, je knihovna posixových vláken. Pro použití bariér je však třeba definovat symbol _XOPEN_SOURCE na hodnotu 600 nebo vyšší ještě před vložením hlavičkového souboru posixových vláken. Deklarace a inicializace: deklarace / inicializace #define _XOPEN_SOURCE 600
// před načtením pthread.h
#include
deklarace / inicializace pthread_barrier_t barrier; int rc;
// deklarace bariéry // pro uložení návratového stavu
rc = pthread_barrier_init(&barrier, NULL, 3);
// stanovení počtu vláken k synchronizaci
Pokud se má po uvolnění vláken provést nějaká jednorázová akce, lze využít návratové hodnoty čekací funkce, která vrátí právě jednomu vláknu hodnotu PTHREAD_BARRIER_SERIAL_THREAD a ostatním hodnotu nula. Jiná hodnota pak znamená chybový stav. Použití bariér v jednotlivých posixových vláknech: synchronizace – čekání rc = pthread_barrier_wait(&barrier);
// čekání na daný počet vláken
// nyní poběží vlákna souběžně switch (rc) { case PTHREAD_BARRIER_SERIAL_THREAD: // provede se v jediném (nespecifikovaném) vlákně case 0: // provede se ve všech vláknech break; default: // nastala chyba perror("pthread_barrier_wait"); }
7.3 Podmínková proměnná Podmínkové proměnné umožňují vláknům čekat na nějakou událost pomocí operace condition_wait. Událost je signalizována operací condition_signal. Pokud žádné vlákno nečeká, je signál ztracen, proto se používá podmínková proměnná společně s testem, zda je třeba čekat.
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
5/6
25.1.2014
IOSYS_2013: Prostředky programovacích jazyků pro IPC
Protože test na potřebu čekání nutně používá sdílenou proměnnou, je nutné zajistit vzájemné vylučování například pomocí mutexu. deklarace / inicializace bool done = false; cond_t cond;
// stav dokončení // synchronizační podmínková proměnná
mutex_t mutex;
// mutex pro zajištění vzájemné výlučnosti přístupu k proměnným
Kód vlákna provádějícího akci, zde vypočtení hodnoty sdílené proměnné x: x = calculate();
// provedení akce
mutex_lock(mutex);
// zajištění exkluzivního přístupu
done = true;
// nastavení stavu dokončení
condition_signal(cond);
// signalizace dokončení akce
mutex_unlock(mutex);
// uvolnění přístupu
synchronizace – signalizace
Kód vlákna čekajícího na dokončení akce: synchronizace – čekání mutex_lock(mutex);
// zajištění exkluzivního přístupu
if (!done) // pokud akce ještě nebyla dokončena, condition_wait(cond); // čekej na dokončení akce mutex_unlock(mutex); use(x);
// uvolnění přístupu
// použití hodnoty sdílené proměnné x vypočtené jiným vláknem
7.4 Opakování 1. 2. 3. 4. 5. 6.
Definujte koncept monitoru a popište jeho vlastnosti. Popište řešení řízení přístupu do kritické sekce pomocí monitoru. Řešte synchronizaci vláken pomocí monitoru. Popište řešení problému svázaných producentů a konzumentů pomocí monitoru. Popište bariéru a způsob jejich použití. Popište podmínkovou proměnnou a synchronizaci vláken pomocí ní. Naposledy změněno: Pondělí, 7. říjen 2013, 15.20
http://fei-learn.upceucebny.cz/mod/page/view.php?id=5278
6/6