Що таке тупик?


159

Під час написання багатопотокових програм однією з найпоширеніших проблем є тупикові місця.

Мої запитання до громади:

  1. Що таке тупик?

  2. Як ви їх виявляєте?

  3. Ви справляєтесь з ними?

  4. І нарешті, як ви запобігаєте їх виникненню?


Відповіді:


207

Блокування відбувається , коли кілька процесів намагаються отримати доступ до одного ресурсу одночасно.

Один процес втрачається і потрібно чекати, коли інший закінчиться.

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

Отже, приклад:

Ресурс A і ресурс B використовуються в процесі X і Y

  • X починає використовувати А.
  • X і Y намагаються почати використовувати B
  • Y 'виграє' і отримує B першим
  • тепер Y потрібно використовувати A
  • A заблокований X, який чекає Y

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

У базах даних уникайте внесення великої кількості змін у різні таблиці за одну транзакцію, уникайте тригерів та переходьте до читання оптимістичних / брудних / блокування якомога більше.


9
Я використовую тут процес як узагальнення, а не конкретно процес ОС. Це можуть бути потоки, але також можуть бути абсолютно різні програми або підключення до бази даних. Шаблон такий же.
Кіт

1
Привіт, враховуючи цей сценарій: Нитка A блокує ресурс A і має тривалий процес. Нитка B чекає блокування ресурсу А. Використання процесорного часу: 20%, чи можна вважати, що це ситуація з тупиком?
rickyProgrammer

2
@rickyProgrammer ні, це просто звичайне очікування блокування, хоча різниця трохи академічна. B очікування повільно A - це замок, B очікування A чекання B - тупик.
Кіт

Тож тупик - це більше два процеси із заблокованими ресурсами, які очікують звільнення цих ресурсів ..
rickyProgrammer

2
@rickyProgrammer - це замок, який не стане безкоштовним, незалежно від того, скільки часу ви будете чекати, через кругову чергу.
Кіт

126

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

Кримінальна та поліцейська сцена

введіть тут опис зображення

Так просто, коли для двох потоків потрібні два різні ресурси, і кожен з них має блокування ресурсу, який потребує інший, це глухий кут.

Ще одне пояснення тупику на високому рівні: Розбиті серця

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


Якщо нитки належать до різних процесів? Чи можуть нитки, що належать до одного і того ж процесу, також спричинити глухий кут?
lordvcs

1
@diabolicfreak Не має значення, належать нитки до одного процесу чи ні.
Сем Малаєк

2
Іншим прикладом з реального життя можуть бути чотири машини, які переходять на перехрестя двох рівних доріг у чотири сторони одночасно. Кожному потрібно дати дорогу автомобілю з правого боку, тому ніхто не може продовжувати.
LoBo

35

Тупики відбудуться лише тоді, коли у вас є два або більше замків, які можна одночасно отримати, і вони схоплені в іншому порядку.

Способи уникнути тупикових ситуацій:

  • уникайте замків (якщо можливо),
  • уникайте більше одного замка
  • завжди приймайте замки в одному порядку.

Третій пункт щодо запобігання тупиковій ситуації (завжди приймайте замки в тому самому порядку), життєво важливий, про що досить легко забути в практиці кодування.
Цянь Сюй

20

Щоб визначити тупик, спочатку я визначив би процес.

Процес : Як ми знаємо, процес є не що інше, як programвиконання.

Ресурс : для виконання програмного процесу потрібні деякі ресурси. Категорії ресурсів можуть включати пам'ять, принтери, процесори, відкриті файли, магнітофони, компакт-диски тощо.

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

Стан або ситуація з тупиком

введіть тут опис зображення

На наведеній діаграмі є два процеси P1 і p2 і є два ресурси R1 і R2 .

Ресурс R1 виділяється для процесу P1, а ресурс R2 виділяється для процесу p2 . Для завершення виконання процесу P1 потрібен ресурс R2 , тому P1 запит на R2 , але R2 вже призначений P2 .

Таким же чином Процес P2 для завершення його виконання потребує R1 , але R1 вже призначений P1 .

обидва процеси не можуть звільнити свій ресурс до тих пір, поки вони не завершать їх виконання. Тож обидва чекають іншого ресурсу, і вони будуть чекати вічно. Отже, це умова ГРИШОГО .

Для того, щоб стався тупик, повинні бути справжніми чотири умови.

  1. Взаємне виключення - кожен ресурс наразі виділяється саме на один процес, або він доступний. (Два процеси не можуть одночасно контролювати один і той же ресурс або знаходитись у їх критичному розділі).
  2. Зачекайте і почекайте - процеси, в яких зараз зберігаються ресурси, можуть запитувати нові ресурси.
  3. Відсутність попередження. Після того, як процес містить ресурс, він не може бути відібраний іншим процесом або ядром.
  4. Циркулярне очікування - кожен процес чекає отримання ресурсу, який утримується іншим процесом.

і всі ці умови виконуються на наведеній вище схемі.


8

Тупик буває, коли нитка чекає чогось, що ніколи не виникає.

Зазвичай це буває, коли нитка чекає на мютекс або семафор, які ніколи не випускався попереднім власником.

Також часто трапляється, коли у вас виникають ситуації, пов’язані з двома потоками та двома блоками на зразок цього:

Thread 1               Thread 2

Lock1->Lock();         Lock2->Lock();
WaitForLock2();        WaitForLock1();   <-- Oops!

Ви, як правило, виявляєте їх, оскільки речі, які, як ви очікуєте, відбудуться ніколи, або програма висить повністю.


Тупик відбувається, коли нитка чекає на те, що не може відбутися.
Маркіз Лорн

4

Ви можете подивитися ці чудові статті у розділі Тупик . Він є в C #, але ідея все ще така ж і для інших платформ. Я цитую тут для легкого читання

Тупик буває, коли дві нитки чекають ресурсу, який тримає інший, тому жоден не може продовжувати. Найпростіший спосіб проілюструвати це двома замками:

object locker1 = new object();
object locker2 = new object();

new Thread (() => {
                    lock (locker1)
                    {
                      Thread.Sleep (1000);
                      lock (locker2);      // Deadlock
                    }
                  }).Start();
lock (locker2)
{
  Thread.Sleep (1000);
  lock (locker1);                          // Deadlock
}

4

Тупик є поширеною проблемою при багатопроцесорних / багатопрограмових проблемах в ОС. Скажімо, є два процеси P1, P2 та два загальнодоступні ресурси R1, R2, а в критичному розділі обом ресурсам потрібно отримати доступ

Спочатку ОС призначає R1 для обробки P1 і R2 для обробки P2. Оскільки обидва процеси працюють одночасно, вони можуть почати виконувати свій код, але ПРОБЛЕМА виникає, коли процес потрапляє у критичний розділ. Тож процес R1 буде чекати, коли процес P2 випустить R2 і навпаки ... Отже, вони будуть чекати назавжди (УМОВЛЕННЯ РОЗВИТКУ).

Невелика АНАЛОГІЯ ...

Ваша мати (ОС),
ви (P1),
ваш брат (P2),
Apple (R1),
ніж (R2),
критичний розділ (різання яблука ножем).

Твоя мати на початку дає тобі яблуко і ніж для брата.
Обоє радіють і грають (виконуючи свої коди).
Хтось із вас хоче в якийсь момент вирізати яблуко (критичний переріз).
Ви не хочете дарувати яблуко своєму братові.
Твій брат не хоче тобі давати ніж.
Тож ви обидва будете чекати дуже довго-довго :)


2

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


2

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


Я голосую за вас. Ваша відповідь більш лаконічна, ніж вище, оскільки вони заплутують глухий кут за допомогою процесу чи потоку. Хтось каже процес, хтось говорить нитку :)
hainguyen

1

Класична і дуже проста програма для розуміння ситуації з тупиком : -

public class Lazy {

    private static boolean initialized = false;

    static {
        Thread t = new Thread(new Runnable() {
            public void run() {
                initialized = true;
            }
        });

        t.start();

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(initialized);
    }
}

Коли головний потік викликає Lazy.main, він перевіряє, чи клас Lazy був ініціалізований і починає ініціалізувати клас. Тепер основний потік встановлює ініціалізований на false, створює і запускає фоновий потік, метод запуску якого встановлений ініціалізовано в true, і чекає завершення фонового потоку.

Цього разу клас ініціалізується іншим потоком. За цих обставин поточний потік, який є фоновим потоком, чекає на об’єкт Class до завершення ініціалізації. На жаль, нитка, яка робить ініціалізацію, основний потік, чекає завершення фонового потоку. Оскільки два потоки тепер чекають один одного, програма ЗАВЕРШЕНО.


0

Тупиковий стан - це стан системи, в якому жоден процес / потік не здатний виконати дію. Як зазначають інші, тупикова ситуація, як правило, є результатом ситуації, коли кожен процес / потік бажає придбати блокування до ресурсу, який вже заблокований іншим (або навіть тим самим) процесом / потоком.

Існують різні методи їх пошуку та уникнення. Кожен думає дуже важко і / або намагається багато речей. Однак боротися з паралелізмом, як відомо, важко, і більшість (якщо не всі) люди не зможуть повністю уникнути проблем.

Деякі формальніші методи можуть бути корисними, якщо ви серйозно ставитеся до таких питань. Найбільш практичний метод, про який я знаю, - це використовувати теоретичний підхід до процесу. Тут ви моделюєте свою систему деякою мовою процесу (наприклад, CCS, CSP, ACP, mCRL2, LOTOS) і використовуєте доступні інструменти для (моделювання) перевірки на наявність тупикових ситуацій (а можливо, і інших властивостей). Прикладами набору інструментів є FDR, mCRL2, CADP та Uppaal. Деякі сміливі душі можуть навіть довести свою систему без тупика, використовуючи суто символічні методи (доказ теореми; шукайте Овікі-Гріса).

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


0

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


0

Вище деякі пояснення приємні. Сподіваємось, це також може бути корисним: https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html

У базі даних, коли сеанс (наприклад, ora) хоче ресурс, який зберігається іншим сеансом (наприклад, дані), але цей сеанс (дані) також хоче ресурс, який проводиться першим сеансом (ora). Також може бути більше 2 сеансів, але ідея буде такою ж. Насправді, тупики заважають деяким транзакціям продовжувати працювати. Наприклад: Припустимо, ORA-DATA містить блокування A і запит блокування B, а SKU містить блокування B і запит блокування A.

Дякую,


0

Тупик виникає, коли нитка чекає закінчення іншої нитки і навпаки.

Як уникнути?
- Уникайте заблокованих замків
- уникайте непотрібних замків
- використовуйте потоки join ()

Як ви це виявляєте?
запустіть цю команду в cmd:

jcmd $PID Thread.print

довідка : geeksforgeeks


0

Тупики виникають не просто із замками, хоча це найчастіша причина. У C ++ ви можете створити тупик з двома потоками і без блокування, просто встановивши кожен виклик потоку join () на об'єкт std :: thread для іншого.


0

Контроль сумісності на основі блокування

Використання блокування для контролю доступу до спільних ресурсів схильне до тупикових ситуацій, і сам планувальник транзакцій не може запобігти їх виникненню.

Наприклад, системи реляційних баз даних використовують різні блокування для гарантії властивостей ACID транзакцій .

Незалежно від того, яку реляційну систему баз даних ви використовуєте, блокування завжди отримуватиметься під час зміни (наприклад, UPDATEабо DELETE) певного запису таблиці. Без блокування рядка, зміненого поточною транзакцією, Atomicity буде порушена .

Що таке тупик

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

введіть тут опис зображення

Оскільки обидві транзакції знаходяться у фазі придбання блокування, жодна з них не звільняє блокування до отримання наступної.

Відновлення від ситуації, що склалася

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

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

Навіть якщо Threadклас виставляє stopметод, цей метод був застарілий з Java 1.1, оскільки він може спричинити залишення об'єктів у непослідовному стані після зупинки потоку. Натомість Java визначає interruptметод, який діє як натяк, оскільки нитка, яка переривається, може просто ігнорувати переривання і продовжувати його виконання.

З цієї причини програма Java не може відновитись із ситуації, що склалася, і відповідальність розробника додатка є замовляти запити на придбання блокування таким чином, що ніколи не може виникнути тупикова ситуація.

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

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

На відміну від JVM, транзакція з базою даних розроблена як атомна одиниця роботи. Отже, відкат залишає базу даних у послідовному стані.

Більш детально про цю тему ознайомтеся і з цією статтею .


-2

Mutex по суті - це замок, що забезпечує захищений доступ до спільних ресурсів. Під Linux типом даних mutex для потоку є pthread_mutex_t. Перед використанням ініціалізуйте його.

Щоб отримати доступ до спільних ресурсів, вам потрібно заблокувати мутекс. Якщо мютекс уже заблокований, виклик заблокує потік, поки не буде розблокована мютекс. Після завершення відвідування спільних ресурсів ви повинні їх розблокувати.

Загалом, існує кілька неписаних основних принципів:

  • Отримайте блокування перед використанням спільних ресурсів.

  • Тримати замок якомога коротше.

  • Відпустіть замок, якщо потік поверне помилку.


3
Це описує блокування, а не тупик.
Маркіз Лорнський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.