280 likes | 716 Views
Конкурентно Програмиране. Семафори: използване за решаване на основни синхронизационни проблеми. Задача за обядващите философи.
E N D
Конкурентно Програмиране Семафори: използване за решаване на основни синхронизационни проблеми Конкурентно програмиране 2005
Задача за обядващите философи • Постановка на задачата: Петима философи прекарват времето си като мислят или се хранят. Последното правят около кръгла маса, в средата на която е поставена купа със спагети. Пред всеки философ има чиния, а между всеки две чинии – една вилица. За да може да яде спагети, всеки философ се нуждае от две вилици, като има право да ползва тези, които са от двете страни на неговата чиния. • Тук трябва да се решат следните синхронизационни проблеми: - всяка вилица да се използва най-много от един философ; - да не се допуска deadlock, т.е. да се окаже, че всеки философ е взел една вилица и чака да се освободи втората, което никога няма да стане; - да е гарантирано, че никой философ няма да умре от глад. • Илюстрация на проблема за възникването на deadlock: • Процесите са вdeadlock ако чакат събитие, което никога няма да настъпи. Най-чесно възникването на deadlock се свързва с управление на ресурсите. Конкурентно програмиране 2005
Необходими условия за възникване на deadlock: - Монополен достъп до ресурсите; - Процесът държи едни ресурси докато чака да получи други; - Ресурсите не могат да бъдат отнемани насилствено от процес, който ги държи чакайки; - Има затворен кръг от процеси, всеки от които държи ресурс, искан от следващия процес в кръга. - Едновременно наличие на горните условия. • Техниките за предпазване от възникването на deadlockса основани на нарушаване на някое от тези условия. • Техниките за избягване на deadlockсе състоят в мониториране на разпределението на ресурсите така, че да се открива потенциалната поява на deadlock и да се предотвратява. Конкурентно програмиране 2005
Решение на задачата за обядващите философи със семафори • Първо решение: общ ресурс е всяка една от вилиците, съответно нейната употреба се обявява за КУ и се защитава с отделен семафор. Semaphore fork [5] = {1,1,1,1,1}; Process Philosopher_i while (true) { think(); P.fork[i]; P.fork[(i+1)%5]; eat(); V.fork[i]; V.fork[(i+1)%5]; } End Philosopher_i; • При каква последователност от изпълнения на действията на процесите възниква deadlock? Конкурентно програмиране 2005
Възможни решения за предпазване от възникването на deadlock: - да се получават едновременно двете вилици; - да се разкъса кръга от процеси, всеки от които е заел единия ресурс и чака достъп до другия: - един от процесите да размени реда, в който се опитва да вземе вилиците, например като всеки посяга първо към вилицата с по-малък номер; - процесите с четни номера да вземат първо лявата си вилица, а тези с нечетни номера – първо дясната; - да се ограничи броя на едновременно седящите около масата философи до 4. Това може да стане за сметка на добавяне на още един семафор-брояч, който управлява достъпа до масата: Semaphore table = 4; Process Philosopher_i P.table; . . . . . . . V.table; end Philosopher_i Конкурентно програмиране 2005
Задача Читатели/Писатели • Модел на работа с общи дани – конкурентно изпълнение на неограничен брой процеси: Читатели, които само четат данните и Писатели, които ги променят. • Изискванията са данните да не се ползват едновременно от: - двама Писатели; - Писател и Читатели. • Решенията имат за цел: - да подсигурят горните изисквания; - да не налагат недопустимо намаление на конкурентността. • Първо решение: Semaphore rw=1; Process Reader Process Writer P.rw; P.rw; readData(); writeData(); V.rw; V.rw; End Reader end Writer • Недопустимо ограничаване на конкурентния достъп до данните. Конкурентно програмиране 2005
Второ решение – отслабване на ограничението: Semaphore rw=1, mutex=1; int nR=0; // number of active Readers Process Reader . . . . . . . . . P.mutex; nR++; if (nR==1) P.rw; V.mutex; readData(); P.mutex; nR--; if (nR==0) V.rw; V.mutex; . . . . . . . . End Reader Process Writer . . . . . . . . . P.rw; writeData(); V.rw; . . . . . . End Writer • Позволено е на повече Читатели да имат конкурентен достъп до данните. • Въпроси: - Как и къде блокират Читателите и Писателите? - Какво става при напускане на Писател? - Кой има приоритет? Конкурентно програмиране 2005
Читатели/Писатели – предаване на щафетата • Предаване на щафетата – метод, който: - позволява да се решават различни синхронизационни проблеми; - води до решения, които лесно се променят така, че да се смени стратегията на планиране. • Определяме предикат, характеризиращ “добрите” и “лошите” състояния на системата. Нека nR - е броят на активните Читатели nW - е броят на активните Писатели “Лоши” състояния:(nR>0 && nW>0) || (nW>1) “Добри” състояния:RW: (nR=0 || nW==0) && (nW<=1) RW е глобален инвариант на системата Reader: < await (nW==0) nR++;> read < nR--; > Writer: < await (nR==0 && nW==0) nW++;> write < nW--; > Конкурентно програмиране 2005
В < > са означени атомарни действия на процесите. • await(B) S;имасмисъл: условието В е гарантирано при изпълнението на S. • “Предаването на щафетата” използва SPB за осигуряване на ВИ, реализация на await(B) и контрол на реда, по който се събуждат блокираните процеси. • Въвежда се: - един двоичен семафор за контрол на достъпа до атомарните действия; - за всяко условие /гард/ В: - един семафор с начална стойност 0; - един брояч с начална стойност 0. Семафорите общо формират един SPB. int nR=0, nW=0; Semaphore entry=1, // CS control semR=0, // delay Readers semW=0; // delay Writers // SPB: 0<= entry+semR+semW<=1 int dR=0, // number of delayed Readers dW=0; // number of delayed Writers Конкурентно програмиране 2005
Process Reader while (true) { // await (nW==0) => nR++ P.entry; if (nW>0) { dR++; V.entry; P.semR; } nR++; signal(); readData(); // nR— P.entry; nR--; signal(); } end Reader Process Writer while (true) { // await (nR==0 && nW==0) => nW++ P.entry; if (nR>0 || nW>0) { dW++; V.entry; P.semW; } nW++; signal(); writeData(); // nW— P.entry; nW--; signal(); } end Writer Конкурентно програмиране 2005
Какво прави signal - решава на кого да предаде щафетата: - на следващ Читател; - на следващ Писател; - да я остави. signal() { // awaken a Reader? if (nW==0 && dR>0) { dR--; V.semR; } // awakan a Writer? else if (nR==0 && nW==0 && dW>0) { dW--; V.semW; } // put baton down else V.entry; } Конкурентно програмиране 2005
Читатели/Писатели – Условен критичен участък resource Control: {int nR=0; boolean isWriting=false;} Process Writer with Control when (nR==0 & !isWritimg) do isWriting=true; writeData(); with Control when (true) do isWriting=false; End Writer; Process Reader with Control when (!isWritimg) do nR++; readData(); with Control when (true) do nR--; End Reader; Конкурентно програмиране 2005
Задачата за спящия бръснар • Постановка на задачата: В бръснарски салон работи един бръснар и има няколко стола за чакащи. Посетител, който влезе в салона и види, че в момента бръснарят подстригва някого сяда и чака, а ако няма свободни столове си тръгва. Ако няма други клиенти, посетителят може да завари бръснаря да дреме, тогава го събужда и сяда за подстригване. Когато бръснарят свърши да подстригва един клиент, той го изпраща и кани следващия, ако има такъв, иначе сяда в стола си и задрямва. • Задачата е илюстрация на типа отношения клиент-сървер между конкурентните процеси. Взаимодействието на процесите – рандеву, носи името си от това, че два процеса трябва “да се срещнат” в дадена точка от своето изпълнение, за да могат да продължат коректно работата си с изпълнение на “общо действие”. Това става за сметка на забавяне на процеса, който първи е пристигнал на мястото на срещата. • Следва просто решение на задачата с използване на семафори за синхронизиране на процеса “бръснар” и процесите “посетители”. Semaphore mutex=1; // за взаимно изключване Semaphore customers=0, // бръснарят чака клиент barber=0; // клиентите чакат бръснар int numChairs= n, waiting=0;// брой чакащи клиенти Конкурентно програмиране 2005
Задачата за спящия бръснар – решение със семафори Process Customer_i while (true) { P.mutex; // иска достъп до 'waiting' if (waiting<numChairs){ // ако има свободен стол - чака waiting++; // увеличава броя на чакащи клиенти V.customers; // събужда бръснаря, ако спи V.mutex; // освобождава достъпа до 'waiting' P.barber; // чака ако бръснарят не е свободен getHairCut(); // клиентът получава услугата } else V.mutex; // иначе напуска } end Customer; Process SleepingBarber while (true) { P.customers; // задрямва ако няма клиенти P.mutex; // иска достъп до 'waiting' waiting--; // намалява броя на чакщите клиенти V.barber; //бръснарят е готов да подстригва V.mutex; // освобождава 'waiting' cutHair(); // сърверът обслужва } end SleepingBarber; Конкурентно програмиране 2005
Задача за разпределение на ресурси - Планировчик • Две основни операции: - заемане на ресурс: request(param) await (resource available) take units - освобождаване на ресурс: release(param) return units • Пример - Shortest-Job-Next Resource Allocator за единичен ресурс boolean free=true; release (pid) { if (process delayed) awaken one else free=true } request (pid, time) { await (free) take resource free=false} Конкурентно програмиране 2005
boolean free=true; Semaphore entry=1, b [n]={[n] 0}; PriorityQueue q=new PriorityQueue(); request (time, pid) { P.entry; if (!free) { q.enqueue(time, pid); V.entry; P.b[pid]; } free=false; V.entry; } release (pid) { P.entry; if (!q.empty()) { pid=q.dequeue(); V.b[pid]; } else free=true; V.entry; } Конкурентно програмиране 2005