Operační systémy - modelování a algoritmy paralelních výpočtů



Podobné dokumenty
Algoritmizace a programování

Modul Řízení objednávek.

Microsoft Office Project 2003 Úkoly projektu 1. Začátek práce na projektu 1.1 Nastavení data projektu Plánovat od Datum zahájení Datum dokončení

Algoritmizace a programování

-1- N á v r h ČÁST PRVNÍ OBECNÁ USTANOVENÍ. 1 Předmět úpravy

NÁVOD K OBSLUZE MODULU VIDEO 64 ===============================

účetních informací státu při přenosu účetního záznamu,

Principy operačních systémů. Lekce 6: Synchronizace procesů

Výzva k podání nabídek (zadávací dokumentace)

PŘÍLOHA Č. 8A PŘÍLOHA OBLAST INTERVENCE 3.1 A 3.3 K METODICE ZADÁVÁNÍ ZAKÁZEK INTEGROVANÝ OPERAČNÍ PROGRAM,

Podrobný postup pro vygenerování a zaslání Žádosti o podporu a příloh OPR přes Portál farmáře

PŘIJÍMACÍ ŘÍZENÍ. Strana

Výzva zájemcům k podání nabídky a Zadávací dokumentace

Obchodní podmínky společnosti Amazing Travel, s.r.o.

Příloha č. 54. Specifikace hromadné aktualizace SMS-KLAS

Distribuované algoritmy

Komplexní pojištění pro město Uherské Hradiště. Zadavatel: město Uherské Hradiště Sídlo: Masarykovo náměstí 19, Uherské Hradiště IČ:

Uživatelská dokumentace

Číslo zakázky (bude doplněno poskytovatelem dotace) 1 Název programu: Operační program Vzdělávání pro konkurenceschopnost

Ėlektroakustika a televize. TV norma ... Petr Česák, studijní skupina 205

Školní kolo soutěže Mladý programátor 2016, kategorie A, B

SRF08 ultrazvukový dálkoměr

ČÁST PÁTÁ POZEMKY V KATASTRU NEMOVITOSTÍ

1.7. Mechanické kmitání

Výzva pro předložení nabídek k veřejné zakázce malého rozsahu s názvem Výměna lina

L 110/18 Úřední věstník Evropské unie

Výzva k podání nabídky na

Inteligentní zastávky Ústí nad Labem

NÁVOD K OBSLUZE. Obj. č.:

VERZE: 01 DATUM: 05/2014

ODŮVODNĚNÍ VEŘEJNÉ ZAKÁZKY Dostavba splaškové kanalizace - Prostřední Bečva a Horní Bečva, zhotovitel, dle vyhlášky č. 232/2012 Sb.

Android Elizabeth. Verze: 1.3

29 Evidence smluv. Popis modulu. Záložka Evidence smluv

Operační systém z hlediska procesu Mgr. Josef Horálek

VÝZVA K PODÁNÍ NABÍDKY VE VEŘEJNÉ SOUTĚŽI O nejvhodnější návrh na uzavření pachtovní smlouvy na restauraci Oceán a přilehlé stánky

Jak na KOTLÍKOVÉ DOTACE? JEDNODUCHÝ RÁDCE PRO ZÁKAZNÍKY

Vyhláška č. 294/2015 Sb., kterou se provádějí pravidla provozu na pozemních komunikacích

Regenerace zahrady MŠ Neděliště

Metodika testování navazujících evidencí

I. Objemové tíhy, vlastní tíha a užitná zatížení pozemních staveb

Vybavení pro separaci a svoz BRKO

VYR-32 POKYNY PRO SPRÁVNOU VÝROBNÍ PRAXI - DOPLNĚK 6

Napájení požárně bezpečnostních zařízení a vypínání elektrické energie při požárech a mimořádných událostech. Ing. Karel Zajíček

Obchodní podmínky pro spolupráci se společností Iweol EU s.r.o.

Číslicová technika 3 učební texty (SPŠ Zlín) str.: - 1 -

Z A D Á V A C Í D O K U M E N T A C E k výzvě k podání nabídek NÁJEM SKLADOVÝCH A MANIPULAČNÍCH PROSTOR A POSKYTNUTÍ SOUVISEJÍCÍCH SLUŢEB

S t r á n k a 1 I N V E S T I C E D O R O Z V O J E V Z D Ě L Á V Á N Í

Město Horní Bříza. Čl. 1 Úvodní ustanovení

Zadávací dokumentace

1 METODICKÉ POKYNY AD HOC MODUL 2007: Pracovní úrazy a zdravotní problémy související se zaměstnáním

Obecně závazná vyhláška města Žlutice č. 2/2011 Požární řád obce

Všeobecné obchodní podmínky portálu iautodíly společnosti CZ-Eko s.r.o.

Notebooky a mobilní zařízení 2015

Popis realizace- 41 Tísňová péče ŽIVOT 90.doc

Silnice č. II/635 Mohelnice Litovel (kř. Červená Lhota)

Metodika pro nákup kancelářské výpočetní techniky

Směrnice kvestorky AMU č. 1/2004

Základní stavební prvky algoritmu

Město Mariánské Lázně

Návod k použití aplikace MARKETINGOVÉ PRŮZKUMY.CZ

Abeceda elektronického podpisu

ZADÁVACÍ DOKUMENTACE

MOBILNÍ KOMUNIKACE STRUKTURA GSM SÍTĚ

Název veřejné zakázky: Sdružené služby dodávky zemního plynu pro Mikroregion Střední Haná na rok 2013

Výzva k podání nabídky

Vláda nařizuje podle 133b odst. 2 zákona č. 65/1965 Sb., zákoník práce, ve znění zákona č. 155/2000 Sb.:

Budování aplikačních rozhraní pro obousměrnou komunikaci mezi ERMS a jejich vztah k Národnímu standardu pro komunikaci mezi ERMS.

Manuál uživatele čipové karty s certifikátem

NÁVRHOVÝ PROGRAM VÝMĚNÍKŮ TEPLA FIRMY SECESPOL CAIRO PŘÍRUČKA UŽIVATELE

1. Název veřejné zakázky: 2. Identifikační údaje zadavatele: 3. Specifikace předmětu veřejné zakázky, zadávací podklady:

21. Číslicový měřicí systém se sběrnicí IEEE 488 (základní seznámení)

SMĚRNICE EVROPSKÉHO PARLAMENTU A RADY 2009/76/ES

ZADÁVACÍ DOKUMENTACE

Český úřad zeměměřický a katastrální vydává podle 3 písm. d) zákona č. 359/1992 Sb., o zeměměřických a katastrálních orgánech, tyto pokyny:

D R A Ž E B N Í V Y H L Á Š K U

ODŮVODNĚNÍ VEŘEJNÉ ZAKÁZKY

Novinky verzí SKLADNÍK 4.24 a 4.25

VÝKLADOVÁ PRAVIDLA K RÁMCOVÉMU PROGRAMU PRO PODPORU TECHNOLOGICKÝCH CENTER A CENTER STRATEGICKÝCH SLUŽEB

Všeobecné obchodní podmínky od

OBEC HORNÍ MĚSTO Spisový řád

Praxe při zadávání veřejných zakázek - nejčastější chyby žadatelů/příjemců

1. kolo soutěže probíhá: od :00:00 hod do :59:59 hod

Z A D Á V A C Í D O K U M E N T A C E k výzvě k podání nabídek

statutární město Děčín podlimitní veřejná zakázka na služby: Tlumočení a překlady dokumentů

3 Vývojová prostředí, základní prvky jazyka Java, konvence jazyka Java

- regulátor teploty vratné vody se záznamem teploty

POZVÁNKA NA MIMOŘÁDNOU VALNOU HROMADU

Konzistence databáze v nekonzistentním světě

Vzdělávání v oblasti veřejných zakázek dle postupu uvedeného v Příručce pro příjemce

ZADÁVACÍ DOKUMENTACE A POKYNY PRO ZPRACOVÁNÍ NABÍDKY

MORAVSKOSLEZSKÝ KRAJ KRAJSKÝ ÚŘAD 28. října 117, Ostrava

VÝZVA K PODÁNÍ NABÍDKY. Stavební úpravy turistické ubytovny TJ Valašské Meziříčí dokončení rekonstrukce

Obchodní podmínky. pro prodej zboží prostřednictvím on-line obchodu umístěného na internetové adrese

Pravidla hry RICOCHET

ZADÁVACÍ DOKUMENTACE K ZAKÁZCE ZADÁVANÉ DLE PRAVIDEL PRO VÝBĚR DODAVATELŮ OPPI A SUBSIDIÁRNĚ DLE ZÁKONA Č. 137/2006 SB

Stroje, technická zařízení, přístroje a nářadí

PALETOVÉ REGÁLY SUPERBUILD NÁVOD NA MONTÁŽ

DAŇOVÉ AKTULITY Daň z přidané hodnoty

VI. Finanční gramotnost šablony klíčových aktivit

Zadávací dokumentace pro podlimitní veřejnou zakázku na dodávky

Transkript:

Operační systémy - modelování a algoritmy paralelních výpočtů texty pro distanční studium Doc. Ing. Cyril Klimeš, CSc. Ostravská univerzita v Ostravě, Přírodovědecká fakulta Katedra informatiky a počítačů

OBSAH 1 MEZIPROCESOVÁ KOMUNIKACE A SYNCHRONIZACE... 4 2 OBECNÁ PROBLEMATIKA SYNCHRONIZACE... 5 3 METODY GRAFICKÉHO ZNÁZORNĚNÍ PARALELISMU... 7 3.1 ZNÁZORNĚNÍ POMOCÍ POSTUPOVÉHO PROSTORU... 7 3.2 ZNÁZORNĚNÍ POMOCÍ PETRIHO SÍTÍ... 8 4 KLASICKÉ SYNCHRONIZAČNÍ ÚLOHY... 1 4.1 PRODUCENT - KONZUMENT... 1 4.2 ČTENÁŘI PÍSAŘI (READERS-WRITERS)... 11 4.3 PROBLÉM HLADOVÝCH FILOZOFŮ (THE DINING PHILOSOPHERS PROBLEM)... 13 5 NÁSTROJE MEZIPROCESOVÉ KOMUNIKACE A SYNCHRONIZACE... 15 5.1 VZÁJEMNÁ NEPŘÍSTUPNOST VZÁJEMNÉ VYHRAZENÍ ČEKÁNÍM NA ČINNOST... 16 Zákaz přerušení.... 16 Zamykání pomocí proměnné... 16 Přísná výměna.... 16 Instrukce TSL... 17 Deadlock ztuhnutí systému.... 18 5.2 KRITICKÉ SEKCE MUTEXY... 19 5.3 DESAKTIVACE A AKTIVACE (SLEEP A WEAKUP)... 2 Semafory... 21 5.4 UDÁLOST - EVENT... 26 6 KOMUNIKACE MEZI PROCESY... 3 6.1 SPOLEČNÁ OBLAST PAMĚTI... 3 6.2 MONITOR... 3 6.3 ZASÍLÁNÍ ZPRÁV A SIGNÁLY... 32 6.4 POŠTOVNÍ SCHRÁNKA MAILBOX... 33 6.5 SETKÁNÍ SOUBĚH (RENDEVOUS)... 34 6.6 ALARMY, ČASOVAČE... 35 6.7 ROURA (PIPE)... 36 7 POUŽITÍ VLASTNOSTI PROSTŘEDKŮ MEZIPROCESOVÉ SYNCHRONIZACE... 38 8 PŘÍLOHA... 4 8.1 PETRIHO SÍTĚ... 4 Analýza Petriho sítě... 42 Klasické techniky analýzy Petriho sítí... 44 Modifikované Petriho sítě... 47 8.2 IF THEN PRAVIDLA... 49 8.3 SIMULÁTOR PETRIHO SÍTÍ HPSIM... 54 Menu File... 55 Menu Edit... 55 Menu View... 56 2

Menu Tools...56 Menu Simulation...57 Menu Extra - nastavení editoru...58 3

1 Meziprocesová komunikace a synchronizace V mnoha operačních systémech může současně běžet mnoho procesů a v systému může existovat mnoho instancí jednoho programu (jeden program může být spuštěn několikrát současně). Každý proces má vyhrazen svůj paměťový prostor a k systémovým prostředkům přistupuje prostřednictvím volání jádra operačního systému. Současný běh několika různých procesů je typickým rysem pro aplikace v reálném čase. Tyto procesy mohou být navzájem nezávislé nebo nějakým způsobem může záviset běh jednoho procesu na běhu jiného procesu. Běh jednoho procesu má tedy vliv na běh druhého a naopak. Potom vyvstává potřeba mít k dispozici mechanismy pro: synchronizaci dvou nebo více procesů navzájem, předávání dat mezi procesy. Často jsou tyto dva mechanismy kombinovány. Například pokud jeden proces požaduje data po druhém procesu, musí čekat dokud nejsou data dostupná, teprve potom může dojít k jejich výměně. Procesy, které spolu navzájem komunikují, mohou přímo sdílet adresový prostor nebo mohou ke své komunikaci využívat sdílených souborů nebo paměťových modulů. Protože přístup jednotlivých procesů k těmto datům je asynchronní, může vést k narušení jejich konzistence. Aby k tomuto narušení nedošlo, je nutné vhodnými prostředky operačního systému zajistit koordinovaný přístup jednotlivých procesů k těmto sdíleným prostředkům. Tento koordinovaný přístup však znamená určitá omezení pro procesy, které k těmto datům přistupují. Omezení spočívá především v tom, že proces nemůže sdílená data měnit kdykoli, ale pouze se souhlasem ostatních procesů, případně operačního systému. Nezbytným požadavkem pro zajištění komunikace mezi procesy je sdílení a ochrana prostředků zdrojů. Při sdílení prostředků se budeme zabývat problematikou: kritických sekcí úseky programů, kdy se sdílenými prostředky proces komunikuje, zastavením činnosti systému (ztuhnutím) deadlock kdy zdroje jsou chybně chráněny proti současnému přístupu. Při komunikaci s prostředky je nutno dodržet určitá pravidla: pouze jeden proces v daném čase může mít přístup k chráněnému prostředku zdroji, procesy zůstávají vzájemně nezávislé, zastavení jednoho procesu neovlivní zpracování ostatních procesů. U procesů je nutné zajisti: bezpečnost, životaschopnost. 4

2 Obecná problematika synchronizace Nekoordinovaný přístup ke sdíleným prostředkům může vést k častým chybám. Odstranění těchto chyb je možné provést synchronizací přístupu procesů ke sdíleným objektům. Přístup ke sdíleným prostředkům bude regulérní, pokud budou tyto procesy splňovat Bernsteinovy podmínky, tedy aby sdílené prostředky jednotlivých procesů byly použity pouze pro operace čtení. V praxi tyto Bernsteinovy podmínky znamenají tak velké omezení, že jsou pro mnoho úloh nesplnitelné a málokdy se používají. Pokud však procesy Bernsteinovy podmínky důsledně splňují, konzistence sdílených dat je zaručena. U procesů, které nesplňují Bernsteinovy podmínky, je nutno zajistit konzistenci dat jiným způsobem. Pro ukázku jak mohou vypadat procesy, které tyto podmínky nesplňují, poslouží následující příklad. Mějme dva procesy P1 a P2 sdílející společnou proměnnou. Proces P1 čte cyklicky každou sekundu hodnoty z A/D převodníku a provádí jejich součet. Proces P2 po 1 min. tento součet zobrazí. #define ADRESA _PORTU x3. int Soucet; while (1) { Soucet += inp (ADRESA_PORTU); Sleep(1; }... while (1) { printf ( Soucet je %d/n, Soucet); // Proces P2 Soucet = ; Sleep (6); }. Jak můžeme vidět, procesy Bernsteinovy podmínky nesplňují, protože oba zapisují do proměnné Soucet. V případě, že procesy budou běžet v operačním systému s preemptivním plánovačem, tedy k přepnutí procesů může dojít po skončení kterékoliv strojové instrukce, může dojít k nastavení chybné hodnoty proměnné Soucet. Možná implementace příkazu: Soucet += inp (ADRESA_PORTU); může být následující: registrl = inp(adresa_portu); registrl = regitrl + Soucet; Soucet = registrl; 5

Potom příznaky printf ( Soucet je % d/n, Soucet), Soucet += inp (ADRESA_PORTU; a Soucet = ; mohou být provedeny např. v takovémto sledu: printf ( Soucet je % d/n, Soucet); P2 registrl = inp(adresa_portu); P1 registrl = registrl + Soucet; P1 Soucet = ; P2 Soucet = registrl; P1 Je zřejmé, že příkaz vynulování proměnné Soucet po jejím zobrazení se neprojeví. Při následujícím sledu příkazů se zase neprojeví čtení hodnoty z A/D převodníku. printf ( Soucet je % d/n, Soucet); P2 registrl = inp(adresa_portu); P1 registrl = registrl + Soucet; P1 Soucet = registrl; P1 Soucet = ; P2 Odstranění těchto chyb je možné pomocí synchronizačních nástrojů. Tedy v použití koordinovaného přístupu ke sdíleným prostředkům. Pokud procesy nesplňují Bernsteinovy podmínky, je třeba vždy analyzovat možné kolize a ty potom odstranit synchronizačními nástroji. Procesy sdílí nějakou společnou oblast operační paměti, soubor nebo jiný systémový prostředek - zdroj. Pro využití tohoto systémového prostředku platí soutěžní podmínky. Příkladem může být spolupráce procesů s jedním V/V zařízením tiskový spoiler (Simultaneous Periphrial Operations On Line) Sdílení prostředků definuje nalezení cesty, jak zakázat více než jednomu procesu zápis nebo čtení sdílených dat v daném časovém okamžiku. Problém stanovení soutěžních podmínek může být také formulován abstraktní cestou. Ta část programu, kde je požadován přístup k sdíleným prostředkům se nazývá kritická sekce. Je potřeba určit způsob, jak dva procesy mohou být ve svých kritických sekcích současně soutěžní podmínky. Spolupráce paralelních procesů musí být korektní a musí efektivně využívat sdílená data. Je potřeba splnit 4 podmínky: žádné dva procesy nesmí být současně uvnitř svých kritických sekcí, nejsou žádné předpoklady o relativní rychlosti procesu nebo počtu CDU, žáden proces běžící mimo svou kritickou sekci neblokuje jiné procesy, žáden proces by neměl čekat neomezeně dlouho na vstup do své kritické sekce. 6

3 Metody grafického znázornění paralelismu Slovní vyjádření problémů synchronizace procesů není někdy dostačující a přesné. Pro lepší a názornější představu o možných kolizích bývá vhodné použít pro rozkreslení běhu procesů některé grafické metody. Jednou z možností grafického vyjádření je použití postupového prostoru. Tato metoda umožňuje přehledně graficky znázornit zakázané sekce, do kterých se procesy při běhu mohou dostat. Tento způsob je však použitelný pouze pro dva, maximálně tři procesy. Při větším počtu procesů je vhodné pro grafické znázornění jejich toku a synchronizace použití Petriho sítí. 3.1 Znázornění pomocí postupového prostoru Postupový prostor dvou procesů je znázorněn kartézskou soustavou souřadnic, kde každá osa je přiřazena právě jednomu procesu. Obecně má postupový prostor dimenzi n, kde n je počet procesů, které znázorňuje. To je důvod, proč tohoto grafického znázornění lze použít maximálně pro tři procesy. Na obrázku 18 je vidět postupový prostor procesů vedených v předchozím příkladu. Osa x je přiřazena procesu P1, osa y pak procesu P2. Paralelnímu běhu procesů zde odpovídá postupová cesta. Každý bod této postupové cesty ukazuje pozici, ve které se běh daného procesu nachází. Tvar postupové cesty závisí na přepínání kontextu. U jednoprocesorového systému je postupová cesta složena z pravoúhlých úseček. Obecně má tvar neklesající funkce. Vyznačený obdélník určuje zakázanou sekci oblast, kterou by postupová cesta neměla projít. V praxi to znamená, že v době průchodu postupové cesty kolem hrany zakázané sekce nesmí dojít k přepnutí mezi procesy, jichž se tato postupová cesta týká (přepnutí jiného procesu nemá vliv). Z takového grafického vyjádření pak máme velmi přesnou představu o umístění synchronizačních nástrojů, které zamezí nežádoucímu přepnutí kontextu, tedy k nekoordinovanému přístupu jednotlivých procesů ke sdíleným prostředkům. 7

P2 Sleep Print S= Sleep Zakázaná oblast Postupová cena Sleep P(port) reg.=reg.+s S=reg. Sleep P1 Obr. 1. Znázornění běhu aplikací pomocí postupového prostoru 3.2 Znázornění pomocí Petriho sítí Výhodnějším modelem znázornění paralelního běhu aplikací se jeví použití Petriho sítí. V příloze tohoto textu jsou vysvětleny základní definice Petriho sítí. Na obrázku 2 je vidět znázornění paralelního běhu dvou procesů pomocí Petriho sítě. Petriho síť lze znázornit grafem, obsahujícím tři typy prvků: Grafy sestávající ze tří typů prvků: uzly umožňují popsat stavy systému, v programu odpovídají jednotlivým příkazům, přechody modelují možnost změny stavu systému, orientované hrany propojují uzly a přechody, definují cesty. 8

A C KSP KS Q B D Obr. 2 Zázornění běhu aplikací pomocí Petriho sítě (problém kritické sekce) Pro znázornění běhu programu se využívá tzv. značené Petriho sítě. Každému prvku v síti je přidělen určitý počet značek, které jsou realizovány černými tečkami. Běh programu je znázorňován posunem černých teček jednotlivými uzly. Postup z jednoho uzlu do druhého lze provést, jestliže je splněna podmínka přechodu mezi nimi přechod je otevřen. Přechod je otevřen, jestliže všechny prvky, které do přechodu vstupují, obsahují alespoň tolik teček, kolik z něj vystupuje. Otevření přechodu způsobí v síti změnu značkování. Změna značkování probíhá následujícím způsobem: z každého uzlu je odebráno tolik teček, kolik je přiřazeno hranám do následujícího přechodu, do každého uzlu je předáno tolik teček, kolik do něj vstupuje s orientovanými hranami z přechodů. Paralelní běh procesů se v grafu projeví existencí více teček. Petriho sítí je možné snadno vyjádřit konkrétní část programu, kde vznikají požadavky na synchronizaci procesů. Oproti postupovému prostoru lze Petriho sítě použít i pro znázornění více procesů. Pro popis celého běhu paralelních aplikací je však potřeba zachytit pohyb tečky všemi místy grafu. To bývá zvláště u složitějších procesů velmi náročné. Ke znázornění běhu 9

aplikace pomocí Petriho sítí se často používá simulace pomocí programů navržených k těmto účelům. 4 Klasické synchronizační úlohy Pro detailnější popis problematiky synchronizace procesů budou v následujících odstavcích popsány klasické problémy, se kterými se lze při vytváření paralelních aplikací skoro vždy setkat. Každý příklad synchronizační úlohy je znázorněn Petriho sítí. 4.1 Producent - konzument Někdy tato úloha také bývá nazývána jako problém omezené vyrovnávací paměti- bufferu. Jedná se o jednosměrnou asynchronní komunikaci mezi procesy pomocí úseku paměti omezené délky (omezeného bufferu). Producent zapisuje položky do tohoto bufferu, konzument položky naopak odebírá. Ve vztahu producent-konzument můžeme také najít určitou symetrii. Při obecnějším pohledu na tuto úlohu lze říci, že producent produkuje plné položky pro příjemce, naopak konzument vytváří prázdné položky pro producenta. Asynchronní přístup zde znamená, že oba pracují nezávisle na sobě. Pokud je buffer prázdný (neexistují plné položky), je konzument nucen čekat, pokud je naopak buffer plný (neexistují prázdné položky), je producent nucen čekat. Jejich činnost však musí být synchronizována. Ve znázornění pomocí Petriho sítě je použito dvou uzlů znázorňujících prázdné a plné položky. Součet teček v obou těchto uzlech (prázdné a plné) udává kapacitu bufferu. produce_data insert_data into_ buffer S_empty S_full remove_data From buffer consume_data producent konzument Obr. 3. Producent - konzument 1

Pohyb teček v grafu probíhá následujícím způsobem: Producent před zápisem položek odebere jednu tečku z uzlu prázdné a po zápisu přidá jednu tečku do uzlu plné. Konzument naopak před odebráním vyjme jednu tečku z uzlu plné a po odebrání přidá jednu tečku do uzlu prázdné. Úloha producent-konzument má praktické uplatnění všude tam, kde spolu procesy komunikují asynchronně, při vyrovnávání rychlostí produkce a zpracování dat. Příkladem takové úlohy v měřící aplikaci může být např. komunikace mezi procesem zajišťujícím kontinuální vzorkování z A/D převodníku a procesem zajišťujícím odesílání dat do jiného počítače ke zpracování pomocí rozhraní Ethernet. Kontinuální vzorkování představuje producenta, odesílání dat po komunikačním médiu konzumenta. Rychlost producenta je stále stejná, rychlost konzumenta může být velmi rozdílná v závislosti na zatížení Ethernetu. Výpadky v komunikaci jsou pak odstraněny pomocí vyrovnávacího bufferu. Obecně, čím větší je velikost bufferu, tím větší mohou být výpadky v komunikaci. Aby nedocházelo k zaplňování bufferu, musí být průměrná rychlost odebírání položek větší nebo rovna rychlosti zápisu těchto položek. 4.2 Čtenáři písaři (Readers-Writers) Tato úloha se objevuje v procesech sdílejících společné datové struktury. Některé procesy tato data modifikují písaři a některé procesy z těchto dat pouze čtou čtenáři. Synchronizace mezi těmito procesy musí respektovat následující pravidla: pokud písař data zapisuje, nesmí zapisovat žádný jiný písař, pokud písař data zapisuje, nesmí tato data číst žádný čtenář, pokud čtenář data čte, nesmí do nich žádný písař zapisovat, pokud čtenář data čte, může libovolný jiný čtenář tato data číst také. Čtení může být tedy povoleno více čtenářům najednou, zápis v daném čase může provádět pouze jeden písař, ostatní písaři i čtenáři musí čekat na ukončení operací tohoto písaře. Model této úlohy Petriho sítí (obr.4 a 5) vypadá následovně: Každý čtenář odebere před operací čtení z kontrolního uzlu jednu tečku. Po ukončení čtení tuto tečku vrátí zpět do kontrolního uzlu. Každý písař čeká na dokončení operací všech čtenářů nebo jiného písaře a před operací zápisu z kontrolního uzlu odebere všechny tečky (znemožní jakékoli další čtení nebo zápis). Po ukončení zápisu vrátí všechny tyto tečky zpět do kontrolního uzlu. Celkový počet teček odpovídá maximálnímu počtu čtenářů (č max). 11

Čtenář 1 Čtenář 4 Zapisovatel.. čtení čtení zápis Obr. 4 Čtenáři - Písaři Čtenář 1 Čtenář 4 Zapisovatel čtení čtení čtení čtení zápis Obr. 5 Čtenáři - Písaři 12

Z načrtnutého schématu jsou vidět možné problémy při řešení této úlohy. Může dojít k umoření písaře vlivem velmi dlouhé doby čekání na ukončení operací čtenářů. Čtenáři se mohou postupně střídat, takže jejich operace nemusí nikdy skončit. Při žádosti písaře o zápis je tedy třeba zajistit, aby žádný čtenář nezačal se sdílenými daty pracovat. 4.3 Problém hladových filozofů (The Dining Philosophers Problem) Představme si pět filozofů sedících okolo kulatého stolu. Všechen svůj čas tráví přemýšlením nebo jedením.u každého filozofa je miska rýže. Zprava i zleva má filosof k dispozici jednu hůlku ke konzumaci rýže. Hůlky musí filozofové sdílet, neboť mezi nimi je vždy jenom jedna. Filozof, pokud se chce najíst, musí se zmocnit hůlek po své pravé i levé ruce (jednou hůlkou se nenají, jiné jsou pro něj příliš daleko). V danou chvíli může filozof sebrat pouze jednu hůlku (každý filozof pracuje sekvenčně, takže nemůže vzít obě najednou). Pokud má obě hůlky, může se nasytit, poté odložit hůlky a dál přemýšlet. Pokud jsou hůlky používány, je nucen čekat až je sousední filozofové uvolní. Model této úlohy pomocí Petriho sítě je znázorněn na obrázku 22. Filozofové jsou zde označeni čísly 1 až 5, hůlky jsou prezentovány jako sdílené objekty S. Filozofové se mohou nacházet ve třech stavech: čekání na hůlky, jedení, přemýšlení. F5 Filosof F1 talíř F4 problém vidlička F2 F3 Obr. 6. Problém hladových filozofů 13

Při řešení této úlohy je třeba zajistit, aby se každý filozof občas najedl a neumřel hlady. Může také dojít k zablokování všech, např. pokud všichni uchopí hůlku po své pravé ruce, hůlky po své levé ruce by se potom nedočkali. čeká S čeká S čeká S čeká S čeká S jí jí jí jí jí přemýšlí přemýšlí přemýšlí přemýšlí přemýšlí Obr. 7 Problém hladových filozofů model pomocí Petriho sítě Úlohu lze řešit např.: snížením počtu filozofů při zachování stejného počtu hůlek, dovolit filozofovi vzít hůlku pouze tehdy, jsou-li volné obě, řešit asymetricky přístup k hůlkám, lichý filozof by uchopil nejprve levou hůlku a pak pravou, sudý filozof naopak. Pokud bude úloha vyřešena jedním z výše uvedených způsobů nedojde k jejímu zablokování. 14

5 Nástroje meziprocesové komunikace a synchronizace Operační systémy, které podporují paralelní běh více procesů zpravidla obsahují synchronizační nástroje, pomocí kterých lze výše uvedené synchronizační úlohy vyřešit. Tyto nástroje se ve větších nebo menších obměnách vyskytují ve všech současných operačních systémech, které paralelní běh více aplikací podporují, a lze je rozdělit do několika skupin popsaných v následujících odstavcích. Jednotlivé nástroje si jsou v zásadě velmi podobné, různé charakteristiky jejich chování jsou určujícím faktorem pro jejich nasazení do různých aplikací. Obecně řečeno, tyto nástroje zajišťují koordinovaný postup jednotlivých procesů ke sdíleným prostředkům (proměnným, souborům, atd.). Tento koordinovaný přístup jde vždy na úkor efektivity běhu aplikací, neboť jednotlivé procesy jsou nuceny čekat na pokyny, které jim dovolí pokračovat ve svém zpracování. Aby například nedošlo ke ztrátě konzistence sdílených dat, je nutné zajistit vzájemně jednoznačný přístup k těmto datům. Pokud možno tak, aby nedošlo ke ztrátě efektivity běhu aplikací. Použití synchronizačních nástrojů podporovaných operačním systémem umožňuje efektivnější sestavení aplikací. Jednotlivé procesy nemusí trávit čas v dotazovacích smyčkách, kde zjišťují stav sdílených proměnných, jejichž hodnoty signalizují k čemu v systému došlo. Namísto toho mohou být ve stavu čekání na aktivaci prostřednictvím nějakého synchronizačního nástroje. Neubírají tedy zbytečně čas procesoru, který může být využit pro jiné činnosti. Mohlo by se říci, že nejlepší způsob návrhu aplikace je tedy ten, kdy jednotlivé procesy nedělají vůbec nic dokud v systému nedojde k něčemu, co by je mohlo zajímat. Tento přístup nemusí být vždy nejefektivnější. Například v multiprocesorových systémech může být naopak výhodné nechat jednotlivé procesy, běžící na různých procesorech, probíhat v cyklech jejich kódu. V takovém případě při aktivaci nedochází k přepnutí kontextu, které může znamenat významnou časovou prodlevu. Jednotlivé procesy potom běží v dotazovacích smyčkách a uvedený způsob synchronizace se nazývá kruhové blokování spinlock. Například dvě aplikace (označme A,B) sdílejí velký blok dat. Provádí-li aplikace A v tomto bloku změnu, je z důvodu zachování konzistence těchto dat nutné uzamknout tento blok pro zápis aplikace B (úloha čtenář-písař). Aplikace B je tedy nucena čekat i v případě, že bude manipulovat se zcela jinou částí sdíleného bloku než aplikace A, což by při logické úvaze vůbec nemusela. Z hlediska efektivity je tedy vhodnější rozdělit tento blok na několik nezávislých částí a k těmto částem přistupovat samostatně. 15

5.1 Vzájemná nepřístupnost vzájemné vyhrazení čekáním na činnost Zatímco jeden proces je činný v příslušné sdílené paměti ve své kritické sekci, žádný jiný proces nebude vstupovat do své kritické sekce, aby způsobil problémy při zpracování sdílených dat. Tuto úlohu můžeme řešit několika způsoby: Zákaz přerušení. Je to nejjednodušší řešení. Po vstupu do své kritické sekce proces zakáže přerušení-hardwarové zamknutí. Nemůže však vzniknout ani přerušení od hodin a procesor nemůže přepínat žádné procesy. Používá se proto pouze v jádře operačního systému a je omezeno na několik instrukcí např. pro uložení registrů, aktualizaci proměnných nebo seznamů. Nedá se použít jako mechanizmus vzájemného vyhrazení mezi uživatelskými procesy. Zamykání pomocí proměnné. Druhé řešení vzájemné nepřístupnosti je softwarové zamknutí. K zamykání je použita jednoduchá sdílená proměnná, která je na počátku ve stavu -false. Jestliže proces vstupuje do své kritické sekce, bude se nejprve testovat zamknutí této proměnné. Jestliže je proměnná ve stavu nastaví se proměnná na I - true a proces vstoupí do své kritické sekce. Jestliže je proměnná ve stavu I, bude proces čekat tak dlouho, dokud se její stav nezmění na. To znamená, že indikuje, že žádný proces není v kritické sekci. Přísná výměna. Třetím způsobem vzájemného vyhrazení je metoda přísné výměny. Celočíselná proměnná f1 kontroluje přístup do kritické sekce. Na začátku proces zkoumá stav proměnné f1. Při zjištění, že je ve stavu (false), stoupí do kritické sekce. Proces1 rovněž zjistí, že je f1 ve stavu (false), ale testuje ji dále ve smyčce, dokud se f1 nedostane do stavu 1 (true). Nepřetržité testování proměnné, čekání na příslušnou hodnotu až se nastaví, se nazývá čekání na činnost (busy waiting). Může se použít při dostatečném volném času procesoru. Příklad: while (true) { while (f1!=) / * čekání */ critical_section ( ); f1 =1; noncritical_section; }... while (true) { while (f1! =1) / * čekání */ critical_section ( ); f1 =; 16

noncritical_section; } Uvedený způsob ovšem není požadovaným řešením problému. Lepší algoritmus lze dostat použitím dvou proměnných f1 a f2. Může ovšem vést k situaci ztuhnutí procesů tzv. deadlock. Hodnota false je přiřazena k f1 a f2 před testem f1 = true a f2 = true. Deadlock a současný přístup k zablokovanému (chráněnému) prostředku jsou dva symetrické problémy vztažené na extrémní situace. Problém lze řešit třemi proměnnými f1, f2 a f3. Algoritmus Dekker Dijstra nebo Petrsonovo řešení. Příklad: #define FALSE #define TRUE 1 #define N2 / * počet procesů */ int f1; / * který f1 je to * / int f2 [N]; / * všechny poč. hod. * / enter_region (process) int process; / * proces číslo nebo 1 */ { int other; / * číslo jiného procesu * / other= 1 process; / * opačný process * / f 2[process] = TRUE; / * potvrzení zájmu * / f 1 = process; / * nastavení flegu * / while ( f1 = = process & & f2 [other] = =TRUE) / * nulování * / } leave_region (process) int process; / * proces opouští kritickou sekci */ { f2 [process] = FALSE; / * indikace odchodu z kritické sekce */ } Instrukce TSL Problém lze rovněž řešit s využitím hardwaru. Instrukce TSL ( test and set lock ) nebo TAS ( test nad set ) pracuje následovně. Přečte obsah paměťového slova v registru a pak uloží nenulovou hodnotu na tuto paměťovou desku. Takto operace čtení slova a jeho uložení je nedělitelná. Žádný jiný proces nemá přístup k příslušnému paměťovému slovu, dokud instrukce neskončí. Procesor při zpracování instrukce TSL zamkne paměťovou sběrnici, aby zabránil ostatním procesorům přístup k paměti, dokud instrukce není ukončena. Při použití instrukce TSL je využita sdílená proměnná flag pro koordinaci přístupu ke sdílené paměti. Je-li flag roven, může každý proces nastavit flag na 1 použitím instrukce TSL a pak číst nebo zapisovat do sdílené paměti. Po ukončení operace nastaví proces flag zpět na např. použitím instrukce mov. 17

Příklad: enter_region: tsl register, flag na1 kopie flagu do registru a nastavení flagu cmp register, # je flag nula jnz enter_region není-li nula, zamknutí, smyčka ret návrat k volajícímu, vstup do kritické sekce leave_region: mov flag, # ret uložení do flagu návrat k volajícímu Pravidla pro přístup ke kritické sekci: o když proces hodlá vstoupit do kritické sekce, dostane povolení to udělat, ovšem v konečném čase, o pouze jeden proces v daném okamžiku může vstoupit nebo pobývat v kritické sekci, o proces zůstává v kritické sekci konečnou a přesně stanovenou dobu. Deadlock ztuhnutí systému. Některé nebo všechny procesy v systému čekají na nějakou událost. Všechny procesy mohou čekat nekonečně dlouho v podmínce dedlock. Jiný případ deadlocku nastane tehdy, jestliže všechny procesy běží, ale nevykazují žádný pokrok (obr. 23). Procesy stále testují podmínku, která se nemění. Pro vznik deadlocku je nutné splnit několik podmínek, nejsou-li splněny nemůže nastat: o Současný přístup. V systému jsou prostředky, které mohou být použity v daném časovém okamžiku pouze jedním procesem. o Nepremptivní vyhrazení. Prostředek může být uvolněn pouze procesem, který si jej vyhradil. o Postupné vyhrazení. Proces si může vyhradit potřebné prostředky v daném čase. o Vyhrazení v opačném pořadí. Procesy si mohou vyhradit prostředky v opačném pořadí. 18

Obr. 8 Znázornění deadlocku situací na křižovatce Tyto čtyři principy mohou způsobit deadlock. Čtvrtý případ vede k deadlocku nejsnadněji, první proces požaduje prostředky v pořadí A B, druhý proces požaduje prostředky v opačném pořadí B A. První čeká na uvolnění B a druhý na uvolnění A v nekonečné smyčce. Procesy nevykazují žáden pokrok. 5.2 Kritické sekce mutexy Problém kritické sekce je ve své podstatě naznačen v předcházejícím textu při výkladu obecné problematiky synchronizace. Kritická sekce je také naznačena při výkladu grafického znázornění paralelismu. Kritická sekce je část běhu procesu, ve kterém je nežádoucí běh procesu jiného, který by mohl negativně ovlivnit běh procesu původního (porušení konsistence sdílených dat, nekoordinovaný přístup ke sdílené proměnné apod.). Problém kritické sekce tedy spočívá v zákazu běhu procesů, které by toto mohly provést. Nebo obecněji, pouze jejich části, která toto může provést. Grafické znázornění kritické sekce pomocí postupového prostoru je uvedeno na obrázku 18, pomocí Petriho sítě na obrázku 19. Kritickou sekcí je část kódu procesu, která přistupuje je sdíleným prostředkům (společné proměnné, soubory, atd.). Ve vyjádření běhu aplikace pomocí postupového prostoru musí každá aplikace tuto část projít mimo tzv. zakázanou sekci oblast. Přístup k těmto prostředkům v daném čase musí mít vždy maximálně jeden proces. Je tedy nutné zajistit vzájemné vyhrazení (mutual exclusion) přístup k těmto prostředkům. Každý proces, který obsahuje kritickou sekci, by měl obsahovat následující část kódu:....... Entry (Critical_Section); / * Cekani na prideleni prava vykonat svou kritickou sekci * /....... / * Vykonani sve kriticke sekce * / Leave (Critical Section); / * Uvolneni kriticke sekce * / 19

....... Nástroje jednotlivých operačních systémů pro vyřešení problému kritické sekce mohou být v implementaci různé. Zpravidla se jedná o nejjednodušší synchronizační nástroj, který je v daném operačním systému k dispozici. Je charakteristický tím, že je binární. Kritická sekce (mutex) je buď signalizována anebo není. Tím je jasně dáno, zda je sdílený prostředek obsazen nebo je volný. Každý proces, který chce vykonat svou kritickou sekci, musí čekat na uvolnění sdíleného prostředku kritické sekce (mutexu) a po skončení tento objekt uvolnit. Na implementaci v konkrétním operačním sytému potom závisí, je-li možné nastavit maximální dobu čekání (timeout) na přidělení kritické sekce (mutexu) a zamezit tak zatuhnutí procesu (deadlock). Zda se objekt, zajišťující tento způsob synchronizace, nazývá kritická sekce, mutex, nebo zcela jinak, závisí na implementaci. Důležitá je vlastnost, že operační systém zajistí přidělení tohoto objektu v daném čase vždy maximálně jednomu procesu. 5.3 Desaktivace a aktivace (sleep a weakup) Dvojice nepřerušitelných systémových volání sleep a weakup umožňuje přístup do kritické sekce. Sleep je systémové volání, umožňující blokování, tj. proces bude suspendován, dokud jej jiný proces neaktivuje. Volání wakeup má jeden parametr, proces je aktivován. Alternativně oba sleep i wakeup mají jeden parametr, paměťová adresa je použita pro prohození volání sleep a wakeup. Lze použít pro problém komunikace mezi producentem a konzumentem. Příklad: #define N 1 /* počet buněk v bufferu */ int count = ; /* počet položek v bufferu */ producer ( ) { while (TRUE) { produce_item ( ); /* generace další položky */ if ( count = = N) sleep ( ); /* jestliže je buffer plný desaktivace */ enter_item ( ); /* vložení položky do bufferu */ count = count + 1; /* přírustek čitače položek v bufferu */ if (count = = 1) wakeup (consumer);/* byl buffer prázdný? */ } } consumer ( ) { while (TRUE) { if (count = = ) sleep ( ); /* jestliže je buffe prázdný desaktivace */ 2

*/ remove_item ( ); /* vezmi položku z bufferu */ count = count 1; /* ubýtek čitače položek v bufferu if (count = = N 1) wakeup (producer); /* byl buffer plný? */ consume_item ( ); /* tisk položky */ } } Semafory Synchronizační nástroj typu semafor je tvořen proměnnou, která může nabývat hodnotu vždy větší nebo rovnou nule (definoval Djjkstra v r. 1965). Práce s objektem typu semafor umožňuje tři operace: inicializace semaforu, nastavení proměnné na počáteční hodnotu, čekání procesu na přidělení semaforu a jeho dekrementace, inkrementace semaforu. Poslední dvě jmenované operace jsou atomické, což znamená, že tyto operace může provádět v daném čase pouze jeden proces. Semafor se typicky používá pro sledování volných prostředků. Zjednodušené použití semaforu bude ukázáno na řešení úlohy producentkonzument (obr. 2). Při řešení této úlohy se využívá dvou semaforů (PRAZDNE, PLNE), které jsou používány pouze těmito dvěma procesy. Úloha spravuje vyrovnávací paměť (BUFFER) o kapacitě N prvků. Na začátku je semafor PRAZDNE inicializován na hodnotu N, semafor PLNE na hodnotu nula. Semafory zajišťují, aby producent nemohl zapisovat prvky do plného bufferu a konzument nemohl číst prvky z prázdného bufferu. Celá úloha probíhá následujícím způsobem: Producent čeká na semafor PRAZDNE, je-li tento semafor větší než nula (v paměti BUFFER jsou k dispozici prázdné prvky), zapisuje jeden prvek a inkrementuje semafor PLNE (dává najevo, že v paměti BUFFER je o jeden prvek více). Konzument čeká na semafor PLNE, je-li tento semafor větší než nula (v paměti BUFFER jsou k dispozici plné prvky), čte jeden prvek a inkrementuje semafor PRAZDNE (dává najevo, že v paměti BUFFER je o jeden prvek méně). Dojde-li k situaci, kdy semafor PRAZDNE nabude hodnoty nula (BUFFER je zcela zaplněn), producent je nucen čekat na přidělení alespoň jednoho prvku ze strany konzumenta (inkrementace semaforu PRAZDEN). Totéž platí analogicky i v případě konzumenta. Kód úlohy producent-konzument potom vypadá následujícím způsobem:..... 21

Init_Sema(PRAZDNE, N) /* Inicializace semaforu PRAZDNE* / Init_Sema (PLNE, ); /* inicializace semaforu PLNE* /..... /* kod producenta */...... while (TRUE) do (Wait_Sema(PRAZDNE)) /* Cekani a nasledna PRAZDNE */ dekrementace semaforu { Write (BUFFER, Prvek); /* Zapis prvku do bufferu* / Signal_Sema (PLNE); /* Inkrementace semaforu PLNE*/ }..... /* kod konzumenta */..... while (TRUE) do (wait_sema (PLNE)); /*Cekani a nasledna PRAZDNE*/ dekrementace semaforu { Read (BUFFER, Prvek); /*Cteni prvku z bufferu*/ Signal_Sema (PRAZDNE); /*Inkremetnace semaforu PRAZDNE*/...... Oproti kritickým sekcím mutexům se implementace semaforu v základní podobě v různých operačních systémech příliš neliší. Rozdíl v implementaci může být např. opět v možnosti nastavení maximální doby čekání (timeout) na přidělení semaforu. Některé operační systémy (např. OS- 9) podporují semafory pouze v binární formě. Aplikace binárních semaforů se potom spíše podobá aplikaci kritické sekce nebo mutexu než semaforu v jeho klasické podobě. Jádrem problému ochrany sdílených prostředků je operace kontroly a změny hodnoty proměnné, jejich oddělení a přerušení v čase. Nepřetržité testování hodnot proměnných zabírá příliš mnoho času procesoru. Semafory byly doporučeny již Dijkstrou jako základní synchronizační princip pro překlenutí problémů s ochrannými proměnnými. Semafor je nejpoužívanější metoda pro synchronizaci procesů. Semafory definují dvě operace, systémová volání, které mohou mít podle implementace různé názvy, nejčastěji se používají: wait, Down, secure nebo lock, signal, Up, release nebo unlock. Výsledek volání wait závisí na okamžité hodnotě semaforu. Je-li jeho hodnota větší než, sníží se touto operací o 1 a proces může pokračovat v činnosti. Jestliže je hodnota semaforu rovna, proces volající wait je pozastaven. Čekání procesu bude trvat tak dlouho, než hodnotu semaforu zvýší jiný proces voláním signal. Pouze potom je možné operací wait opět 22

snížit hodnotu semaforu a pokračovat ve zpracování procesu. Volání signal zvyšuje hodnotu semaforu o 1 a nemá žádný účinek na zpracovávaný proces. Je velmi důležité, že testování a snížení hodnoty pomocí funkce wait se provádí pouze po krocích v rámci jedné operace. Operační systém nepovolí přerušení při zpracování volání wait, testování hodnoty a operace snížení hodnoty proběhne bez přerušení. Operace wait semaforu je totožná s operací TSL, je-li jí hardware počítače vybaven. Signal a wait mají mnemotechnický význam. Signal je spojen s během procesu a wait s jeho využitím. Jestliže semafor má hodnotu, proces musí čekat na signal. Jestliže několik procesů čeká na stejný signal, pouze jeden z nich může pokračovat ve zpracování, když je zadán signál. Závisí to na implementaci. Nejčastější implementací pro využití více než dvěma procesy je doplnění proměnné frontou. Procesy čekají ve frontě FIFO nebo mohou být vybrány z fronty jiným algoritmem k pokračování zpracování, např. náhodně. Semafory samy o sobě neřídí pořadí ve frontě, to určuje příslušná implementace semaforu v daném operačním systému. Obecný semafor Nejčastější implementace obecného semaforu je kombinace fronty a celočíselné hodnoty proměnné: Systémové volání wait nejprve sníží hodnotu semaforu o 1. Je-li výsledná hodnota rovna nule, uloží systémové volání wait identifikační čísla aktivního procesu do fronty semaforu, převede aktivní proces do stavu čekání a vyvolává přeplánování-procesu je odebrán procesor. Tento proces čeká na příslušný signal, který bude volán v jiném procesu. Systémové volání signal nejprve zvýší hodnotu semaforu o 1 a uvolní (release)první proces z fronty semaforu a převede jej do stavu připraven. Vlastně ukončí operaci wait pozastaveného procesu. Příklad: program sem_example var p1: semaphore begin p1:= 1;... while TRUE do (* opakování *) begin (* proces A *) wait (p1); (* chráněný sdílený prostředek *) signal (p1);... end (* proces A *) while TRUE do (* opakování *) begin (* proces B*) 23

wait (p1); (* chráněný sdílený prostředek *) signal (p1);... end (* proces B*)... end. (* sem_example *) Jedna proměnná semaforu postačuje ke koordinaci přístupu porovnáváním různých příznaků zpracovávaných procesů.procesy zpracovávající volání wait jsou zařazeny do fronty čekajících procesů a nespotřebovávají čas CPU pro testování stavu proměnné semafor. Operační systém uvolní proces, když je zavolán odpovídající signal. Jsou-li synchronizovány procesy producent a konzument, musí vždy druhý proces, konzument, počkat až první proces, producent, zapíše data do sdílené oblasti paměti. Producent čeká až do chvíle než je konzument ze sdílené paměti odebere. Tak se oba procesy střídají ve zpracovávání. Zajištění efektivní implementace činnosti procesů producent a konzument je pomocí obecných semaforů jednoduché. Ukážeme si použití jiného typu volání down a up. Pro synchronizaci použijeme tři semafory. První semafor mutex bude řídit přístup do kritické sekce producenta a konzumenta. Jeho počáteční hodnotu nastavíme na 1. Další dva semafory indikují stav vyrovnávací paměti. Semafor empty indikuje stav prázdný a jeho počáteční hodnota bude dána počtem prázdných buněk vyrovnávací paměti např. N. Semafor full indikuje stav plný a jeho počáteční hodnota je dána počtem zaplněných buněk, na počátku tedy. Příklad: #define N 1 /* počet buněk v bufferu */ typedef int semaphore; /* deklarace semaforu */ semaphore mutex = 1; /* řízení přístupu do krit. sekce */ semaphore empty = N; /* čitač prázdných buněk bufferu */ semaphore full = ; /* čitač plných buněk bufferu */ producer ( ); { int item; while (TRUE) { produce_item (&item); /* generace vstup do bufferu */ down (&empty); /* snížení čitače prázdný */ down (&mutex); /* vstup do krit.sekce */ enter_item (item); /* vložení nové položky do bufferu */ up (&mutex); /* opuštění kritické sekce */ up (&full); /* zvýšení čitače plný */ } 24

} consumer ( ) { int item; while (TRUE){ down (&full); /* snížení čitače plný */ down (&mutex); /* vstup do kritické sekce */ remove_item (&item); /* odebrání položky z bufferu */ up (&mutex); /* opuštění kritické sekce */ up (&empty); /* zvýšení čitače prázdný*/ consume_item (item); /* použití položky */ } } Řešení je možné i se dvěma semafory. První A bude řídit přístup a je inicializován na a druhý B je inicializován velikostí sdílené paměti. Sdílená paměť je využita nejlépe, budou-li oba procesy pracovat stejně rychle, nejsou prodlevy. Jestliže se konzument zpozdí, umožní hodnota semaforu B producentovi generovat data bez přerušení, dokud nenaplní celou sdílenou paměť, pak bude pozastaven a musí čekat na konzumenta. Jestliže producent poběží pomaleji, bude konzument pozastaven, až bude sdílená paměť prázdná. Často nestačí informace o tom, že proces čeká na nějaký semafor, ale je nutné vědět, o který semafor se jedná. Každý semafor má tedy své identifikační číslo. Číslo semaforu se uloží do tabulky procesu(identifikačního segmentu). Binární semafory Semafor mutex v předcházejícím příkladu slouží pouze pro řízení přístupu do kritické sekce a může mít pouze dvě hodnoty, které můžeme označit jako jeho stavy. Takový typ semaforu označujeme jako binární semafor. Lze to porovnat se skutečným semaforem, kdy svítí buď zelená nebo červená. Může signalizovat stav, zda kritická sekce je otevřena nebo uzavřena. Implementace systémových volání může být opět různá. Činnost si vysvětlíme na volání unlock a lock, které lépe vyjadřují funkci binárního semaforu: lock, unlock. Systémové volání lock nejprve testuje hodnotu semaforu. Další činnost záleží na implementaci semaforu, zda počáteční hodnota je 1 nebo. V minulém příkladu byla jedna, nyní si ukážeme druhý případ, kdy bude počáteční hodnota nula a funkce semaforu bude trochu odlišná. Jestliže semafor byl nulový, svítila zelená, nastaví se na jedničku, svítí červená, volání je ukončeno (nepřerušitelná operace) a proces vstoupí do své kritické sekce. Jestliže obsahoval 1, svítila červená, uloží identifikační číslo procesu do fronty semaforů a pak jej suspenduje (proces suspenduje sám sebe). Bude-li počáteční hodnota semaforu 1, zelená, zachová se postup volání wait, kdy se hodnota semaforu snižuje o 1. Pro lepší pochopení principu jsou uváděny obě možnosti. 25

Systémové volání unlock nejprve ověří, je-li fronta semaforu neprázdná. Je-li tomu tak, vybere z ní první proces a převede jej do stavu připraven. Tato funkce odpovídá volání signal, který ukončuje volání wait. Pokud je fronta prázdná, nastaví volání unlock semafor na nulu pro případ počáteční hodnoty nula. Pro druhý případ zvýší hodnotu semaforu 1, standardní funkce volání signal. Každý proces před vstupem do kritické sekce zavolá systémové volání lock a po ukončení kritické sekce systémové volání unlock. Pro funkci binárního semaforu lze snadno použít i obecný semafor, což odpovídá druhému případu, kdy počáteční hodnota semaforu je rovna1. I když bylo uvedeno, že semafor může nabývat pouze nezáporných hodnot, lze v tomto případě využít i záporných hodnot semaforu a to v případě, že počáteční hodnota semaforu je nula. Každé volání wait sníží hodnotu semaforu o 1, záporná hodnota pak udává počet procesů, které čekají na semafor. Volání signal zvyšuje hodnotu semaforu o 1 až do stavu, kdy na semafor nečeká žádný proces a jeho stav odpovídá původnímu, což je nula, svítí zelená. Z uvedeného je zřejmé, že implementace obecného semaforu může být složitější, aby zabezpečovala možné funkce semaforu. 5.4 Událost - Event Události zpravidla slouží k oznámení jednoho procesu ostatním procesů, že nějaká operace skončila a mohou se provádět operace další. Ukončí-li např. proces zpracování bloku dat, oznámí pomocí služby událostevent tuto skutečnost ostatním procesům a tyto procesy mohou tento blok dat dále používat. Událost event je tedy služba operačního systému, která umožňuje aktivovat vybrané procesy, které na ni čekají. Typickou úlohou, kde můžeme tuto složku využít je úloha čtenáři písaři. Na rozdíl od kritické sekce nebo mutexu událost není žádnému procesu speciálně přidělován. Událost pouze signalizuje jednomu nebo více procesům, že k něčemu došlo. Například aplikace, kdy jeden proces získává data z A/D převodníku a ukládá je do datové struktury, a další procesy data z této struktury zpracovávají. Jeden proces z nich počítá efektivní hodnotu, druhý provádí harmonickou analýzu, třetí počítá průměr, čtvrtý je ukládá do databáze, atd. Vznikne tedy úloha typu jeden písař a N čtenářů. Písař po vytvoření datové struktury potřebuje dát najevo čtenářům, že struktura je kompletní a mohou ji začít zpracovávat. Aby se písař dozvěděl, že může vytvořit další datovou strukturu, bude nejjednodušší, aby všichni čtenáři signalizovali ukončení své činnosti svou vlastní událostí. Písař potom musí čekat na signalizaci ukončení činnosti od všech čtenářů. Kód písaře a čtenářů potom vypadá následujícím způsobem: 26

/* Kod pisare */..... while (!konec) { Cteni_A/D (Data); /* Vytvareni struktury data */ Set_Event (Event Data); /* Aktivace udalosti, která signalizuje platna data pro ostatni procesy */ Wait_Event (Even_Ctenar_1); /* Cekani na ukonceni ctenare 1 */ Reset_Event (Event_Ctenar_1); /* Deaktivace udalosti ctenare 1 */.... Wait_Event (Event_Ctenar_N); /* Cekani na ukonceni ctenare N */ Reset_Event (Event_Ctenar_N); Reset_Event (Event_Data); data*/ }.... /* Kod ctenare 1 */.... while (konec) { Wait_Event (Event_Data); Zpracovani_Ctenare_1(Data); Set_Event (Event_Ctenar_1); }.... /* Kod ctenare N */.... while (!konec) { Wait_Event (Event_Data); Zpracovani_Ctenare_N (Data); Set_Event (Event_Ctenar_N); }.... /* Deaktivace udalosti pro platna Takto uvedený kód je zcela v pořádku pouze na první pohled. Tento kód však může aktivovat čtenáře na jednu událost Event_Data několikrát, než ji stačí písař deaktivovat. Pokud např. čtenář 1 ukončí zpracování dat dříve než ostatní čtenáři a vrací se na příkaz čekání na událost Event_Data, která je stále nastavena, zpracuje tato data podruhé. Operační systémy, pokud mají implementováno volání obsluhující událost, obsahují zpravidla funkci Pulse_Event, která zajistí nastavení události, aktivaci příslušných procesů a desaktivaci této události. Konstrukce programu jednotlivých procesů se potom podstatně zjednoduší. Přistupují-li procesy ke společným datům, mohou být tato modifikována pouze při splnění určitých podmínek, které mohou být odlišné pro různé procesy. Všechny procesy mají následující strukturu: 27

begin wait until condition; modify data; end Přístup ke společným datům musí být chráněn. Možné řešení je takové, že jedním semaforem řídíme přístup ke společným datům a jiným semaforem indikujeme, zda společná data jsou změněna. Všechny procesy přistupují k semaforu voláním mutex (současný přístup) a voláním change (změna dat) stejnou cestou. var mutex, change: semaphore; waiting: integer; begin wait (mutex); while not condition do begin waiting : = waiting + 1; signal (mutex); wait (change); wait (mutex); end; (* operace na společných proměnných *) while (waiting > ) do begin waiting : = waiting - 1; signal (change); end; signal (mutex); end; Příklady realizace služby událost event Službě event mohou být přiřazena dvě volání například await a cause, tato jména volání nejsou všeobecně akceptována a jsou uváděna jako příklad dvou volání. Operací await je proces zařazen do fronty, zatím co se hodnota sdílených dat mění. Změna dat je řízena voláním cause. Po změně dat, tzn. uskutečnění události, jsou uvolněny všechny čekající procesy a ne pouze jeden jako v případě použití semaforu. Událost event může být realizována jak binární proměnnou, tak čítačem (event counter). Služba událost nechrání kritickou sekci před současným přístupem několika procesů, jak je to u semaforů. Tato služba je určena pro jiné synchronizační úlohy, jak již bylo dříve uvedeno, např. písaři čtenáři. Příklad realizace události pomocí proměnných event a semaphore je následující: var mutex: semaphore; change: event; begin while not condition do await (change); 28

wait (mutex); (* operace na společných proměnných *) signal (mutex); end; Událost change je spojena se semaforem mutex. Volání signal semaforu mutex realizuje volání cause (události change). Při každé změně hodnoty události change všechny procesy testují podmínku a pouze procesy, pro které je podmínka splněna, mohou být zpracovávány. Pouze jeden proces může využívat chráněný prostředek, je chráněn semaforem mutex. 29

6 Komunikace mezi procesy Pro vzájemnou komunikaci využívají procesy několik systémových prostředků: společná oblast paměti, služba monitor, služba poštovní schránka mailbox, služba setkání- rendevous, služba zpráva signal, služna alarm a časovač timer, služba roura pipe. 6.1 Společná oblast paměti Různé procesy mohou číst a zapisovat do společné oblasti paměti. Tato oblast může být chráněna pomocí semaforů, tuto službu si takto může realizovat uživatel. 6.2 Monitor Monitor je klasická metoda sdílení prostředků při meziprocesové komunikaci. Umožňuje výměnu informací mezi procesy, které musí být synchronizovány. Monitor zahrnuje vyhrazenou datovou oblast a příslušnou proceduru s výhradním právem práce s daty. Externí procedury nemají přímý přístup k oblasti dat obsluhované službou monitor, ale mohou ji použít pouze prostřednictvím služby monitor. Monitor umožňuje službu v daném okamžiku pouze jedné externí proceduře. Operační systém zajišťuje, aby příslušná procedura monitor nebyla přerušena jiným procesem. Takto volaná procedura monitor nemůže být ukončena před přístupem jiné procedury ke stejným datům. Příklad: Procedure monitor (* příklad monitoru *) var struct1: record; (* chráněná oblast *) procedure write_data (monitor_input); entry; begin... with struct1 do... end procedure read_data (monitor_output); entry; begin... 3

with struct1 do... end; end. (* procedura monitor *) Procedury write_data a read_data jsou definovány jako entry procedury vstupní procedury monitoru. Pouze přes tyto procedury se komunikuje s monitorem. Externí procesy nemají přímý přístup k sdílené datové oblasti structl a interní procedury nejsou explicitně definovány jako entry. Výhodou monitorů je to, že ponechávají sdílení prostředků a synchronizaci procesů na operačním systému, pokud jsou součástí jeho služeb a nemusí se jí zabývat uživatel. Monitory bývají rovněž součástí některých víceúlohových jazyků jako je Concurrent Pascal, kdežto v jiných běžně používaných jazycích jako je C nebo Pascal si jejich vlastní strukturu můžeme naprogramovat. Řešení problému producent-konzument pomocí monitoru: monitor ProducerConsumer condition full, empty; integer count; procedure enter; begin if count = N then wait (full); enter_item; count : = count + 1; if count = 1 then signal (empty); end; procedure remove; begin if count = then wait (empty); remove_item; count : = count 1; if count = N 1 then signal (full); end; count : = ; end monitor; procedure producer; begin while true do begin produce_item; ProducerConsumer.enter; end end; procedure consumer; begin 31

end; while true do begin ProducerConsumer.remove; consume_item; end 6.3 Zasílání zpráv a signály Zasílání zpráv je základní metodou meziprocesové komunikace. Signál je nástrojem meziprocesové komunikace i synchronizace. Proces zašle signál nebo zprávu, která obsahuje parametr s hodnotou. Typické operace, které zasílání zpráv (message passing) umožňují jsou: send (destination, &message), receive (source, &message). Implementace u různých operačních systémů jsou odlišné, zejména co se týká parametrů příkazů. Obdobně to platí i u zasílání signálů. Typické operace, které operace se signály umožňují jsou: send_signal (parametrs) odeslání signálu, receive_signal (parametrs) přijetí signálu. Jednotlivé implementace zasílání signálů se liší především ve způsobu adresace vysílajícího a přijímajícího procesu, formátu zprávy a ve způsobu synchronizace zasílání zpráv. Způsob adresace lze rozdělit do tří částí: symetrická, asymetrická a nepřímá. Při symetrické adresaci je v synchronizačních příkazech uváděna identifikace přijímajícího i vysílajícího procesu. V přijímajícím procesu je uvedena adresa vysílajícího procesu, od kterého má být signál přijat. Při nesymetrické adresaci je uváděna pouze identifikace příjemce. Identifikaci vysílajícího procesu je možné zjisti po přijetí signálů z hodnoty přijatého signálu. V případě nepřímé adresace se uvádí pouze identifikace komunikačního kanálu, který příjem a zasílání zpráv zprostředkovává (např.mailbox). Podle způsobu synchronizace je možné mechanismy zasílání signálů rozdělit na asynchronní a synchronní. Synchronní zasílání zpráv obsahuje oproti asynchronnímu potvrzení přijetí zprávy vysílajícímu procesu. Je opět třeba připomenout, že správu signálů zajišťuje operační systém. Vysílající proces zavolá funkci send_ signal s odpovídajícími parametry a operačním systém zajistí aktivaci příslušného procesu, který na přijetí signálu čeká (je ve stavu spící ve funkci receive_signal). Signál obvykle prochází vyrovnávací pamětí, ve které je dočasně uložen.velikost této paměti bývá zpravidla nastavitelná při vytváření objektu signálu. Přijímací proces tedy nemusí nutně okamžitě zpracovat příchozí signál. V případě nahromadění nezpracovaných signálů může funkce send_signal vrátit chybu nebo může být rozšířena o čekání (úloha typu producent-konzument). 32