Реентрантного замок
Замок реентерабельные один, где процесс может требовать блокировки несколько раз без блокировки на себя. Это полезно в ситуациях, когда нелегко отслеживать, захватили ли вы замок. Если блокировка не является повторной попыткой, вы можете захватить блокировку, а затем заблокировать, когда вы идете, чтобы снова захватить ее, эффективно блокируя ваш собственный процесс.
Reentrancy в целом является свойством кода, в котором он не имеет центрального изменчивого состояния, которое может быть повреждено, если код был вызван во время его выполнения. Такой вызов может быть сделан другим потоком, или он может быть рекурсивно выполнен по пути выполнения, исходящему из самого кода.
Если код зависит от общего состояния, которое может быть обновлено в середине его выполнения, оно не является повторным, по крайней мере, если это обновление может сломать его.
Прецедент для Реентрантных блокировок
(несколько родовых и надуманные) пример заявки на Реентрантный замок может быть:
У вас есть некоторые вычисления с участием алгоритм, который пересекает граф (возможно, с циклами в нем). Обход может посещать один и тот же узел более одного раза из-за циклов или из-за нескольких путей к одному и тому же узлу.
Структура данных подлежит одновременному доступу и может быть обновлена по какой-либо причине, возможно, другим потоком. Вы должны иметь возможность блокировать отдельные узлы для борьбы с потенциальным повреждением данных из-за условий гонки. По какой-то причине (возможно, производительности) вы не хотите глобально блокировать всю структуру данных.
Вы не можете сохранить полную информацию о том, какие узлы вы посетили, или используете структуру данных, которая не позволяет «я был здесь раньше», чтобы отвечать на вопросы быстро.
Примером такой ситуации может быть простая реализация алгоритма Дейкстры с приоритетной очередью, реализованной в виде двоичной кучи или поиска по ширине с использованием простого связанного списка в качестве очереди. В этих случаях проверка очереди для существующих вставок - O (N), и вы не можете делать это на каждой итерации.
В этой ситуации отслеживание того, какие замки вы уже приобрели, дорого. Предполагая, что вы хотите сделать блокировку на уровне узла, механизм блокировки повторного входа облегчает необходимость выяснения того, посетили ли вы узел раньше. Вы можете просто слепо заблокировать узел, возможно, разблокировать его после того, как вы вытащите его из очереди.
Реентрантная мьютексы
Простой мьютекс не Реентрантная, как только один поток может находиться в критической секции в данный момент времени. Если вы возьмете мьютекс, а затем попытайтесь снова захватить его, простой мьютекс не будет иметь достаточной информации, чтобы рассказать, кто его держал ранее. Чтобы сделать это рекурсивно, вам нужен механизм, в котором каждый поток имеет токен, чтобы вы могли узнать, кто захватил мьютекс. Это делает механизм мьютекса несколько более дорогим, поэтому вы не можете делать это во всех ситуациях.
IIRC API-интерфейс потоков POSIX предлагает возможность повторного входа и без повторного входа в мьютексы.
Хотя таких ситуаций, как правило, следует избегать, так как это затрудняет предотвращение взаимоблокировки и т. Д. Threading достаточно сложно в любом случае, не сомневаясь в том, что у вас уже есть блокировка. –
+1, также рассмотрите случай, когда блокировка НЕ реентерабельная, вы можете заблокировать себя, если не будете осторожны. Плюс в C, у вас нет тех же механизмов, что и другие языки, чтобы обеспечить, чтобы блокировка была выпущена столько раз, сколько она приобретается. Это может привести к большим проблемам. – user7116
это точно то, что случилось со мной вчера: я не принимал вопрос о повторном вступлении в рассмотрение и в конечном итоге отлаживал тупик в течение 5 часов ... – vehomzzz