Алгоритм Декера — перший відомий правильний розв'язок задачі взаємного виключення в паралельному програмуванні. Едсгер Дейкстра посилається на голландського математика Теодора Декера як на його винахідника в своєму рукописі про взаємодію між процесами. Він дозволяє двом процесам спільно використовувати одновикористовний ресурс без конфліктів, використовуючи тільки спільну пам'ять для зв'язку.
Передмова
Якщо два процеси намагаються увійти до критичної секції одночасно, алгоритм дозволить увійти лише одному процесу, виходячи з того чия зараз черга. Якщо один з процесів знаходиться в критичній секції, другий буде в доки перший процес не залишить критичну секцію. Це робиться шляхом використання двох прапорців, flag[0] і flag[1], які показують намір увійти до критичної секції, та змінну turn, яка показує який з процесів зараз пріоритетніший.
Псевдокод
flag[0] := false flag[1] := false turn := 0 // or 1 | |
p0: flag[0] := true while flag[1] = true { if turn ≠ 0 { flag[0] := false while turn ≠ 0 { } flag[0] := true } } // критична секція ... turn := 1 flag[0] := false // решта коду | p1: flag[1] := true while flag[0] = true { if turn ≠ 1 { flag[1] := false while turn ≠ 1 { } flag[1] := true } } // критична секція ... turn := 0 flag[1] := false // решта коду |
Процеси показують намір увійти до критичної секції, що перевіряється у зовнішньому циклі. Якщо інший процес не позначив свій намір, до критичної секції можна війти, попри те чия зараз черга. Взаємне виключення буде все одно гарантоване, тому що жоден процес не може увійти до критичної секції перед встановленням свого прапорця (тобто щонайменше один процес увійде в цикл while). Також це гарантує рух уперед через відсутність очікування процесу, який скасував намір увійти до критичної секції. Інакше, якщо змінна другого була встановлена, відбувається вхід до циклу while і змінна turn буде вказувати, кому дозволено увійти до критичної секції. Процес, чия черга не настала, полишає намір увійти до критичної секції доти, доки не настане його черга (внутрішній цикл while). Процеси, чия черга надійшла, виходять з циклу while і входять до своєї критичної секції.
Алгоритм Декера гарантує взаємне виключення, неможливість виникнення взаємних блокувань або ресурсного голоду. Якщо алгоритм був би змінений таким чином, щоб при виконанні дій всередині зовнішнього циклу while не перевірялась умова на рівність нулю змінної turn, тоді виникла б можливість ресурсного голоду. Таким чином всі кроки алгоритму необхідні.
Зауваження
Перевагою цього алгоритму є те, що він не вимагає особливої команди Test-and-set (атомарного читання-і-зміни) і, таким чином, легко переноситься між різними мовами і машинними архітектурами. Недоліком є те, що в оригіналі він призначений тільки для двох процесів, а також використовує замість призупинення процесу. (Використання стану очікування означає, що процес має знаходитися якнайменше часу всередині критичної секції.)
Багато сучасних центральних процесорів виконують операції не послідовно (одна за одною), навіть звертання до пам'яті може здійснюватися зі зміною порядку операцій. Тому цей алгоритм не буде працювати на SMP машинах, обладнаних такими центральними процесорами, без використання бар'єрів пам'яті.
Сучасні операційні системи надають більш загальні та гнучкі примітиви взаємного виключення. Тим не менше, за відсутності реальної конкуренції між процесами, операції входу і виходу з критичної секції із використанням алгоритму Декера дуже ефективні.
Реалізація на
bool threads[2]; int turn; void func(int thread_id) { threads[thread_id] = true; while (threads[1-thread_id]) { // Сюди ми потрапляємо коли ще хтось виявив бажання увійти в критичну секцію // Якщо черга наша, тоді інший процес має відмовитись від свого бажання if (turn != thread_id) { // Наступний рядок обов'язковий, щоб інший процес міг вийти із зовнішнього циклу threads[thread_id] = false; // Якщо черга не наша, очікуємо... while (turn != thread_id) {} threads[thread_id] = true; } } critical_function(); // Ресурс нам більше не потрібен turn = 1-thread_id; threads[thread_id] = false; }
Узагальнення
Дейкстра змінив алгоритм надавши можливість підтримки до N процесів. Через необхідність попереднього визначення N новий варіант підходить для будь-якої кількості процесів, але не більше N, що робить його досить практичним.
На відміну від алгоритму Декера масив flag
має розмір N і складається з елементів із трьома значеннями. Три значення описують відповідні ситуації: пасивний, процес наразі не має потреби критичній секції; із запитом, процес намагається увійти в критичну секцію; і активний, тобто процес виконує критичну секцію.
const int N = .. ; enum F : int { Passive, Requesting, Active } F[] flags = new F[N]; // всі встановлені як пасивні int turn = 0; void EnterCriticalRegion(int i) { int j; do { flags[i] = F.Requesting; // показуємо нашу зацікавленість while(turn != i) // очікуємо на свою чергу if (flags[turn] == F.Passive) turn = i; flags[i] = F.Active; // анонсуємо входження // перевіряємо, що ніхто інший не увійшов for (j = 0; j < N && (j == i || flags[j] != F.Active); j==;); } while (j < N); } void LeaveCriticalRegion(int i) { flags[i] = F.Passive; // лиш вказуємо, що ми закінчили }
Зауважимо, що так само як і базовий алгоритм Декера цей код не буде працювати з сучасними компіляторами і процесорами через високу ймовірність виконання не по черзі. Цей код лиш показує логічну послідовність.
Примітки
- E.W. Dijkstra, Cooperating Sequential Processes [ 4 лютого 2010 у Wayback Machine.], manuscript, 1965. Retrieved 13. May, 2009.
Джерела
- Joe Duffy. 2: Synchronization and Time // Concurrent Programming on Windows. — Addison-Wesley, 2008. — С. 52-53. — ISBN 978-0-321-4348-1.
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
Algoritm Dekera pershij vidomij pravilnij rozv yazok zadachi vzayemnogo viklyuchennya v paralelnomu programuvanni Edsger Dejkstra posilayetsya na gollandskogo matematika Teodora Dekera yak na jogo vinahidnika v svoyemu rukopisi pro vzayemodiyu mizh procesami Vin dozvolyaye dvom procesam spilno vikoristovuvati odnovikoristovnij resurs bez konfliktiv vikoristovuyuchi tilki spilnu pam yat dlya zv yazku PeredmovaYaksho dva procesi namagayutsya uvijti do kritichnoyi sekciyi odnochasno algoritm dozvolit uvijti lishe odnomu procesu vihodyachi z togo chiya zaraz cherga Yaksho odin z procesiv znahoditsya v kritichnij sekciyi drugij bude v doki pershij proces ne zalishit kritichnu sekciyu Ce robitsya shlyahom vikoristannya dvoh praporciv flag 0 i flag 1 yaki pokazuyut namir uvijti do kritichnoyi sekciyi ta zminnu turn yaka pokazuye yakij z procesiv zaraz prioritetnishij Psevdokodflag 0 false flag 1 false turn 0 or 1p0 flag 0 true while flag 1 true if turn 0 flag 0 false while turn 0 flag 0 true kritichna sekciya turn 1 flag 0 false reshta kodu p1 flag 1 true while flag 0 true if turn 1 flag 1 false while turn 1 flag 1 true kritichna sekciya turn 0 flag 1 false reshta kodu Procesi pokazuyut namir uvijti do kritichnoyi sekciyi sho pereviryayetsya u zovnishnomu cikli Yaksho inshij proces ne poznachiv svij namir do kritichnoyi sekciyi mozhna vijti popri te chiya zaraz cherga Vzayemne viklyuchennya bude vse odno garantovane tomu sho zhoden proces ne mozhe uvijti do kritichnoyi sekciyi pered vstanovlennyam svogo praporcya tobto shonajmenshe odin proces uvijde v cikl while Takozh ce garantuye ruh upered cherez vidsutnist ochikuvannya procesu yakij skasuvav namir uvijti do kritichnoyi sekciyi Inakshe yaksho zminna drugogo bula vstanovlena vidbuvayetsya vhid do ciklu while i zminna turn bude vkazuvati komu dozvoleno uvijti do kritichnoyi sekciyi Proces chiya cherga ne nastala polishaye namir uvijti do kritichnoyi sekciyi doti doki ne nastane jogo cherga vnutrishnij cikl while Procesi chiya cherga nadijshla vihodyat z ciklu while i vhodyat do svoyeyi kritichnoyi sekciyi Algoritm Dekera garantuye vzayemne viklyuchennya nemozhlivist viniknennya vzayemnih blokuvan abo resursnogo golodu Yaksho algoritm buv bi zminenij takim chinom shob pri vikonanni dij vseredini zovnishnogo ciklu while ne pereviryalas umova na rivnist nulyu zminnoyi turn todi vinikla b mozhlivist resursnogo golodu Takim chinom vsi kroki algoritmu neobhidni ZauvazhennyaPerevagoyu cogo algoritmu ye te sho vin ne vimagaye osoblivoyi komandi Test and set atomarnogo chitannya i zmini i takim chinom legko perenositsya mizh riznimi movami i mashinnimi arhitekturami Nedolikom ye te sho v originali vin priznachenij tilki dlya dvoh procesiv a takozh vikoristovuye zamist prizupinennya procesu Vikoristannya stanu ochikuvannya oznachaye sho proces maye znahoditisya yaknajmenshe chasu vseredini kritichnoyi sekciyi Bagato suchasnih centralnih procesoriv vikonuyut operaciyi ne poslidovno odna za odnoyu navit zvertannya do pam yati mozhe zdijsnyuvatisya zi zminoyu poryadku operacij Tomu cej algoritm ne bude pracyuvati na SMP mashinah obladnanih takimi centralnimi procesorami bez vikoristannya bar yeriv pam yati Suchasni operacijni sistemi nadayut bilsh zagalni ta gnuchki primitivi vzayemnogo viklyuchennya Tim ne menshe za vidsutnosti realnoyi konkurenciyi mizh procesami operaciyi vhodu i vihodu z kritichnoyi sekciyi iz vikoristannyam algoritmu Dekera duzhe efektivni Realizaciya na C bool threads 2 int turn void func int thread id threads thread id true while threads 1 thread id Syudi mi potraplyayemo koli she htos viyaviv bazhannya uvijti v kritichnu sekciyu Yaksho cherga nasha todi inshij proces maye vidmovitis vid svogo bazhannya if turn thread id Nastupnij ryadok obov yazkovij shob inshij proces mig vijti iz zovnishnogo ciklu threads thread id false Yaksho cherga ne nasha ochikuyemo while turn thread id threads thread id true critical function Resurs nam bilshe ne potriben turn 1 thread id threads thread id false UzagalnennyaDejkstra zminiv algoritm nadavshi mozhlivist pidtrimki do N procesiv Cherez neobhidnist poperednogo viznachennya N novij variant pidhodit dlya bud yakoyi kilkosti procesiv ale ne bilshe N sho robit jogo dosit praktichnim Na vidminu vid algoritmu Dekera masiv flag maye rozmir N i skladayetsya z elementiv iz troma znachennyami Tri znachennya opisuyut vidpovidni situaciyi pasivnij proces narazi ne maye potrebi kritichnij sekciyi iz zapitom proces namagayetsya uvijti v kritichnu sekciyu i aktivnij tobto proces vikonuye kritichnu sekciyu const int N enum F int Passive Requesting Active F flags new F N vsi vstanovleni yak pasivni int turn 0 void EnterCriticalRegion int i int j do flags i F Requesting pokazuyemo nashu zacikavlenist while turn i ochikuyemo na svoyu chergu if flags turn F Passive turn i flags i F Active anonsuyemo vhodzhennya pereviryayemo sho nihto inshij ne uvijshov for j 0 j lt N amp amp j i flags j F Active j while j lt N void LeaveCriticalRegion int i flags i F Passive lish vkazuyemo sho mi zakinchili Zauvazhimo sho tak samo yak i bazovij algoritm Dekera cej kod ne bude pracyuvati z suchasnimi kompilyatorami i procesorami cherez visoku jmovirnist vikonannya ne po cherzi Cej kod lish pokazuye logichnu poslidovnist PrimitkiE W Dijkstra Cooperating Sequential Processes 4 lyutogo 2010 u Wayback Machine manuscript 1965 Retrieved 13 May 2009 DzherelaJoe Duffy 2 Synchronization and Time Concurrent Programming on Windows Addison Wesley 2008 S 52 53 ISBN 978 0 321 4348 1