При написании многопоточных приложений одной из наиболее распространенных проблем являются взаимоблокировки.
Мои вопросы к сообществу:
Что такое тупик?
Как вы их обнаруживаете?
Вы справляетесь с ними?
И, наконец, как вы предотвращаете их появление?
multithreading
concurrency
locking
deadlock
bmurphy1976
источник
источник
Ответы:
Блокировка происходит , когда несколько процессов пытаются получить доступ к одному ресурсу одновременно.
Один процесс проигрывает и должен ждать завершения другого.
Тупиковый происходит , когда процесс ожидания все еще держится на другой ресурс , что первые потребности до него можно закончить.
Итак, пример:
Ресурс A и ресурс B используются процессом X и процессом Y
Лучший способ избежать взаимоблокировок - избегать пересекающихся процессов таким образом. Уменьшите необходимость блокировать что-либо как можно больше.
В базах данных избегайте внесения множества изменений в разные таблицы за одну транзакцию, избегайте триггеров и по возможности переключайтесь на оптимистическое / грязное / nolock чтение.
источник
Позвольте мне объяснить реальный (а не реальный) пример тупиковой ситуации из криминальных фильмов. Представьте, что преступник держит в заложниках, и против этого, полицейский также держит заложника, который является другом преступника. В этом случае преступник не собирается отпускать заложника, если полицейский не отпустит своего друга. Также полицейский не собирается отпускать друга преступника, если только преступник не освободит заложника. Это бесконечная ненадежная ситуация, потому что обе стороны настаивают на первом шаге друг от друга.
Криминальная и полицейская сцена
Проще говоря, когда двум потокам нужны два разных ресурса и каждый из них имеет блокировку ресурса, в которой нуждается другой, это тупик.
Еще одно объяснение высокого уровня тупика: разбитые сердца
Вы встречаетесь с девушкой, и через день после ссоры обе стороны разбиты друг другу и ждут звонка « Мне жаль, и я пропустил» . В этой ситуации обе стороны хотят общаться друг с другом, если и только если одна из них получает вызов « Мне жаль» от другой. Поскольку ни один из них не собирается устанавливать связь и ожидает в пассивном состоянии, оба будут ждать, пока другой установит связь, что приведет к тупиковой ситуации.
источник
Взаимные блокировки возникают только тогда, когда у вас есть два или более замков, которые могут быть обнаружены одновременно, и они захвачены в другом порядке.
Способы избежать тупиков:
источник
Чтобы определить тупик, сначала я бы определил процесс.
Процесс : Как мы знаем, процесс не что иное, как
program
выполнение.Ресурс : Для выполнения процесса программы необходимы некоторые ресурсы. Категории ресурсов могут включать память, принтеры, процессоры, открытые файлы, ленточные накопители, компакт-диски и т. Д.
Deadlock : Deadlock - это ситуация или условие, когда два или более процессов удерживают некоторые ресурсы и пытаются получить дополнительные ресурсы, и они не могут освободить ресурсы, пока не завершат выполнение.
Состояние или ситуация тупика
На приведенной выше схеме есть два процесса P1 и p2 и два ресурса R1 и R2 .
Ресурс R1 выделяется для процесса P1, а ресурс R2 выделяется для процесса p2 . Для завершения выполнения процесса P1 необходим ресурс R2 , поэтому запрос P1 для R2 , но R2 уже выделен для P2 .
Точно так же процесс P2 для завершения своего выполнения требует R1 , но R1 уже выделен для P1 .
оба процесса не могут освободить свой ресурс до тех пор, пока они не завершат свое выполнение. Так что оба ждут других ресурсов и будут ждать вечно. Так что это условие DEADLOCK .
Для возникновения тупика должны быть выполнены четыре условия.
и все эти условия выполняются на диаграмме выше.
источник
Тупик возникает, когда поток ожидает чего-то, что никогда не происходит.
Как правило, это происходит, когда поток ожидает мьютекс или семафор, который никогда не был освобожден предыдущим владельцем.
Это также часто случается, когда вы сталкиваетесь с двумя потоками и двумя блокировками:
Обычно вы обнаруживаете их, потому что то, что вы ожидаете, никогда не произойдет, или приложение полностью зависнет.
источник
Вы можете взглянуть на эту замечательную статью в разделе Deadlock . Это в C #, но идея остается той же для другой платформы. Я цитирую здесь для удобства чтения
источник
Deadlock является распространенной проблемой в многопроцессорных / многопрограммных задачах в ОС. Скажем, есть два процесса P1, P2 и два глобально разделяемых ресурса R1, R2, и в критическом разделе должны быть доступны оба ресурса
Первоначально ОС назначает R1 для обработки P1 и R2 для обработки P2. Поскольку оба процесса работают одновременно, они могут начать выполнять свой код, но ПРОБЛЕМА возникает, когда процесс попадает в критическую секцию. Таким образом, процесс R1 будет ждать, пока процесс P2 освободит R2, и наоборот ... Таким образом, они будут ждать вечно (СОСТОЯНИЕ ОТКЛЮЧЕНИЯ).
Небольшая АНАЛОГИЯ ...
источник
Тупиковая ситуация возникает, когда две нити приобретают блокировки, препятствующие прогрессу любой из них. Лучший способ избежать их - это осторожное развитие. Многие встроенные системы защищают от них, используя сторожевой таймер (таймер, который сбрасывает систему всякий раз, когда она зависает в течение определенного периода времени).
источник
Взаимная блокировка возникает, когда существует круговая цепочка потоков или процессов, каждый из которых содержит заблокированный ресурс и пытается заблокировать ресурс, удерживаемый следующим элементом в цепочке. Например, два потока, которые содержат соответственно блокировку A и блокировку B, и оба пытаются получить другую блокировку.
источник
Классическая и очень простая программа для понимания тупиковой ситуации: -
Когда основной поток вызывает Lazy.main, он проверяет, был ли инициализирован класс Lazy, и начинает инициализировать класс. Теперь основной поток устанавливает значение initialized в значение false, создает и запускает фоновый поток, метод запуска которого устанавливает значение initialized в значение true, и ожидает завершения фонового потока.
На этот раз класс в настоящее время инициализируется другим потоком. При этих обстоятельствах текущий поток, который является фоновым потоком, ожидает объекта Class до завершения инициализации. К сожалению, поток, который выполняет инициализацию, основной поток, ожидает завершения фонового потока. Поскольку два потока теперь ждут друг друга, программа ОТКЛЮЧЕНА.
источник
Тупиковая ситуация - это состояние системы, в котором ни один процесс / поток не может выполнить действие. Как упоминалось другими, взаимоблокировка обычно является результатом ситуации, когда каждый процесс / поток желает получить блокировку для ресурса, который уже заблокирован другим (или даже тем же) процессом / потоком.
Существуют различные методы, чтобы найти их и избежать их. Один очень усердно думает и / или пробует много вещей. Однако общение с параллелизмом общеизвестно сложно, и большинство (если не все) люди не смогут полностью избежать проблем.
Некоторые более формальные методы могут быть полезны, если вы серьезно относитесь к решению подобных проблем. Наиболее практичный метод, который мне известен, - это использование теоретического подхода к процессу. Здесь вы моделируете свою систему на некотором языке процессов (например, CCS, CSP, ACP, mCRL2, LOTOS) и используете доступные инструменты для (моделирования) проверки на наличие взаимоблокировок (и, возможно, некоторых других свойств). Примерами используемых инструментов являются FDR, mCRL2, CADP и Uppaal. Некоторые смелые души могут даже доказать, что их системы зашли в тупик, используя чисто символические методы (доказательство теорем; ищите Овики-Гриза).
Однако эти формальные методы обычно требуют определенных усилий (например, изучение основ теории процессов). Но я думаю, это просто следствие того, что эти проблемы сложны.
источник
Тупиковая ситуация - это ситуация, возникающая, когда доступно меньше ресурсов, как того требует другой процесс. Это означает, что когда количество доступных ресурсов становится меньше, чем запрашивается пользователем, тогда в этот момент процесс переходит в состояние ожидания. Иногда время ожидания увеличивается, и у вас нет никаких шансов выявить проблему нехватки ресурсов. эта ситуация известна как тупик. На самом деле, взаимоблокировка является серьезной проблемой для нас, и она возникает только в многозадачной операционной системе. Блокировка не может происходить в однозадачной операционной системе, поскольку все ресурсы присутствуют только для той задачи, которая в данный момент выполняется ......
источник
Выше некоторые объяснения хороши. Надеюсь, что это также может быть полезно: https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html
В базе данных, когда сеанс (например, ora) хочет ресурс, удерживаемый другим сеансом (например, данными), но этот сеанс (данные) также хочет ресурс, который удерживается первым сеансом (ora). Также может быть задействовано более двух сессий, но идея будет одинаковой. Фактически, Deadlocks препятствуют продолжению работы некоторых транзакций. Например: предположим, что ORA-DATA удерживает блокировку A и запрашивает блокировку B, а SKU удерживает блокировку B и запрашивает блокировку A.
Спасибо,
источник
Взаимная блокировка возникает, когда поток ожидает завершения другого потока, и наоборот.
Как избежать?
- Избегайте вложенных замков
- Избегайте ненужных замков
- Используйте thread join ()
Как вы это обнаружили?
запустите эту команду в cmd:
ссылка : гиксфоргекс
источник
Замки не просто случаются с замками, хотя это самая частая причина. В C ++ вы можете создать взаимоблокировку с двумя потоками без блокировок, просто вызывая каждый поток вызовом join () для объекта std :: thread для другого.
источник
Блокировка параллельного управления
Использование блокировки для управления доступом к общим ресурсам подвержено взаимоблокировкам, и один только планировщик транзакций не может предотвратить их возникновение.
Например, системы реляционных баз данных используют различные блокировки, чтобы гарантировать свойства ACID транзакции .
Независимо от того, какую систему реляционной базы данных вы используете, блокировки всегда будут получены при изменении (например,
UPDATE
илиDELETE
) определенной записи таблицы. Без блокировки строки, которая была изменена текущей выполняющейся транзакцией, атомарность была бы скомпрометирована .Что такое тупик
Как я объяснил в этой статье , взаимоблокировка возникает, когда две параллельные транзакции не могут прогрессировать, потому что каждая ждет, пока другая снимет блокировку, как показано на следующей диаграмме.
Поскольку обе транзакции находятся в фазе получения блокировки, ни одна из них не снимает блокировку до получения следующей.
Восстановление из тупиковой ситуации
Если вы используете алгоритм управления параллелизмом, основанный на блокировках, то всегда существует риск запуска в тупиковой ситуации. Взаимные блокировки могут возникать в любой среде параллелизма, а не только в системе баз данных.
Например, многопоточная программа может зайти в тупик, если два или более потоков ждут блокировок, которые были получены ранее, так что ни один поток не может сделать никакого прогресса. Если это происходит в приложении Java, JVM не может просто заставить поток остановить его выполнение и снять блокировки.
Даже если
Thread
класс предоставляетstop
метод, этот метод считается устаревшим с Java 1.1, поскольку он может привести к тому, что объекты останутся в несогласованном состоянии после остановки потока. Вместо этого Java определяетinterrupt
метод, который действует как подсказка, поскольку поток, который прерывается, может просто игнорировать прерывание и продолжать его выполнение.По этой причине Java-приложение не может восстановиться из ситуации взаимоблокировки, и разработчик приложения обязан упорядочить запросы на получение блокировки таким образом, чтобы взаимные блокировки никогда не возникали.
Тем не менее, система базы данных не может принудительно применить данный порядок получения блокировки, так как невозможно предвидеть, какие другие блокировки определенная транзакция захочет получить дополнительно. Сохранение порядка блокировки становится обязанностью уровня доступа к данным, и база данных может только помочь в восстановлении после тупиковой ситуации.
Механизм базы данных запускает отдельный процесс, который сканирует текущий график конфликтов на предмет циклов ожидания блокировки (которые вызваны взаимными блокировками). Когда цикл обнаружен, ядро базы данных выбирает одну транзакцию и прерывает ее, вызывая снятие блокировок, чтобы другая транзакция могла совершить прогресс.
В отличие от JVM, транзакция базы данных разработана как элементарная единица работы. Следовательно, откат оставляет базу данных в согласованном состоянии.
Для более подробной информации по этой теме, проверьте эту статью .
источник
Mutex по сути является замком, обеспечивающим защищенный доступ к общим ресурсам. В Linux тип данных мьютекса потока - pthread_mutex_t. Перед использованием инициализируйте его.
Чтобы получить доступ к общим ресурсам, вы должны заблокировать мьютекс. Если мьютекс уже заблокирован, вызов заблокирует поток, пока мьютекс не будет разблокирован. По завершении посещения общих ресурсов их необходимо разблокировать.
В целом, есть несколько неписаных основных принципов:
Получите блокировку перед использованием общих ресурсов.
Удерживать замок как можно быстрее.
Снимите блокировку, если поток возвращает ошибку.
источник