ГоловнаСтаттіРозподілені Системи

Задача про філософів у їдальні: Заїдання, Голодування та Як Це Уникнути

П’ять філософів Дейкстри та п’ять паличок ілюструють чотири умови Кофмана для заїдання — і пояснюють, як упорядкування ресурсів, арбітр або обмеження конкуренції вирішують цю проблему по-різному.

mysimulator teamОновлено — червень 2026≈ 8 хв читання▶ Відкрити симуляцію

Уважно мінімальна затримка (Deadlock)

Edsger Dijkstra сформулював проблему п’яти філософів у 1965 році (спочатку це було про стрічкові накопичувачі; обставини з філософами, які сидять навколо столу, стали популярними пізніше, завдяки Тоні Хоуру), щоб ілюструвати затримку (deadlock) та голодування з найпростішою конфігурацією: п’ять філософів сидять навколо круглого столу, між кожною парою сусідніх філософів лежить один вил, і кожному філософу потрібно тримати обидва сусідні вили для їжі. Кожен філософ чергує між думками та їжею, а вил може утримувати лише один філософ одночасно – це ресурс з взаємним виключенням, подібно до замка, рядка бази даних або буфера спільного пам’яті в реальній паралельній системі.

жива демонстрація · пов'язана симуляція● LIVE

Наївне застрявання

Звісно, реалізація передбачає, що кожен філософ піднімає свою ліву виделку, потім праву, їсть і кладе обидві назад. Якщо всі філософи одночасно беруть ліву виделку, то всі п'ять виделок утримуються, і кожен філософ чекає назавжди на праву виделку, яка ніколи не буде віддана – застрявання (deadlock). Це класичне зображення чотирьох умов Коффмана, які повинні виконуватися одночасно для виникнення застрягання: взаємний доступ (виделка служить лише одному філософу), утримання та очікування (утримуючи ліву виделку, чекають на праву), відсутність примусового захоплення (ніхто не може змусити виделку відійти від філософа) і циклічне очікування (кожен філософ чекає на свого сусіда справа, утворюючи цикл).

// наївне: застрягає, якщо кожен філософ одночасно бере ліву pickUp(leftFork); pickUp(rightFork); // блокується назавжди, якщо тримач правої виделки // чекає на свою власну праву виделку (цикл) eat(); putDown(leftFork); putDown(rightFork); Порушення однієї з чотирьох умов запобігає застряганню, і кожен класичний розв’язок порушує іншу.

// naive: deadlocks if every philosopher grabs left simultaneously
pickUp(leftFork);
pickUp(rightFork);   // blocks forever if right fork's holder is
                      // itself waiting on ITS right fork (a cycle)
eat();
putDown(leftFork);
putDown(rightFork);

Впорядкування ресурсів руйнує цикл

Найпростішим рішенням є безпосереднє розривання циклічної очікувальної ситуації: присвоїти виделки номерами від 0 до 4 і вимагати, щоб кожен філософ першим підіймав виделку з нижчим номером незалежно від того, на якій стороні він знаходиться. Таким чином, філософ між виделами 4 і 0 бере виделку 0 першою, а не виделку 4 – це єдина асиметрія, необхідна для запобігання циклічному очікуванню. Цей метод використовується в реальних двигунах баз даних та менеджерах блоків: завжди отримувати блоки у фіксованому глобальному порядку, і цикличної очікувальної ситуації не може виникнути незалежно від кількості конкуруючих потоків.

// resource (fork) ordering — breaks circular wait
const [first, second] = leftFork.id < rightFork.id
  ? [leftFork, rightFork] : [rightFork, leftFork];
pickUp(first);
pickUp(second);
eat();
putDown(second);
putDown(first);

Арбітр і обмеження паралелізму

Друге класичне рішення руйнує ситуацію з очікування-тримання: введено арбітра (офіціанта, як у нараді), від якого філософ повинен отримувати дозвіл перед захопленням будь-якої вилки. Арбітр надає дозвіл лише тоді, коли обидві вилки вільні, роблячи це атомарно. Оскільки жоден філософ ніколи не тримає одну вилку, чекаючи на іншу, застрявання (deadlock) структурно неможливе – але це відбувається за рахунок єдиної глобальної точки синхронізації, яка може стати вузьким місцем при інтенсивному використанні, що є класичною компромісною угодою щодо централізованого блокування.

Третє рішення обмежує паралелізм безпосередньо: дозволяється не більше чотирьох із п’яти філософів одночасно сидіти. З лише чотирма кандидатами на п'ять вилок, гарантовано, що принаймні один філософ матиме обидві сусідні вилки вільними, що руйнує застрявання без необхідності центрального арбітра або порядку вилок – це аналог контролю доступу з точки зору теорії паралелізму.

Затримка проти голодування та живелок

Це три окремі режими відмови, які варто розглядати окремо. Затримка (deadlock) – це ситуація, коли набір процесів у циклі чекає один на одного, нічого не відбувається. Голодування (starvation) – це коли процес постійно втрачає доступ до необхідного ресурсу, навіть якщо система в цілому продовжує прогресувати, наприклад, якщо політика планування завжди віддає перевагу філософам-сусідів. Живелок (livelock) – це коли процеси активно змінюють стан у відповідь один на одного, але при цьому не роблять жодного реального прогресу – два філософи повторювано піднімають та опускають вилку, щоб бути ввічливими один до одного, назавжди. Правильне рішення проблеми філософів із столом має усунути всі три ці режими, а не лише затримку; порядок ресурсів і арбітр обидва це роблять, але наївна схема пріоритетів може усунути затримку, дозволяючи при цьому одному несприятливому філософу голодувати.

Frequently asked questions

Які чотири умови необхідні для виникнення зациклення (deadlock)?

Взаємне виключення (ресурс може бути утримуваний лише одним процесом), утримання та очікування (утримання одного ресурсу під час очікування іншого), відсутність припинення (ресурси не можуть бути силою забрані), і коловий очікування (циклічне очікування процесів один на одного). Усі чотири умови повинні виконуватися одночасно; порушення будь-якої з них запобігає зацикленню, що є точно тим, що роблять порядок ресурсів та рішення арбітра.

Чому нумерування видечок (forks) запобігає зацикленню?

Це усуває симетрію, яка створює коловий очікування. Якщо кожен філософ завжди бере нижчо-номерну видечку першою, той філософ, який би іншим чином замкнув цикл, замість цього діставатиме ту саму видечку, як і сусід, так що принаймні один з них зможе отримати обидві видечки та врешті-решт звільнить їх – не може утворитися циклу.

Чи є зациклення (deadlock) однаковим поняттям із голодуванням (starvation)?

Ні. Зациклення означає, що вся система постійно застрягає без будь-якого прогресу; голодування означає, що система продовжує робити загальний прогрес, але один конкретний процес постійно відмовляється в отриманні ресурсу, який йому потрібен. Рішення, яке запобігає зацикленню, наприклад, погано спроектована пріоритетна схема, все ще може залишати місце для голодування.

Спробуйте наживо

Усе, що вище, працює прямо у вашому браузері — відкрийте Dining Philosophers і змінюйте параметри під час роботи. Нічого не встановлюється, нічого не завантажується на сервер, уся модель живе в одній вкладці.

▶ Відкрити симуляцію Dining Philosophers

Що ви знайшли?

Додати кроки відтворення (опційно)