Повторный мьютекс - Reentrant mutex

В Информатика, то реентерабельный мьютекс (рекурсивный мьютекс, рекурсивная блокировка) - это особый тип взаимное исключение (мьютекс) устройство, которое может быть заблокировано несколько раз одним и тем же процесс / поток, не вызывая тупик.

В то время как любая попытка выполнить операцию «блокировки» на обычном мьютексе (блокировке) либо потерпит неудачу, либо заблокируется, когда мьютекс уже заблокирован, на рекурсивном мьютексе эта операция будет успешной если и только если запирающая нить - это та, которая уже удерживает замок. Обычно рекурсивный мьютекс отслеживает, сколько раз он был заблокирован, и требует выполнения такого же количества операций разблокировки, прежде чем другие потоки могут его заблокировать.

Мотивация

Рекурсивные мьютексы решают проблему невозвращаемость с обычными мьютексами: если функция, которая принимает блокировку и выполняет обратный вызов, сама вызывается обратным вызовом, тупик следует.[1] В псевдокод, это следующая ситуация:

вар m: Mutex // нерекурсивный мьютекс, изначально разблокированный.функция lock_and_call (i: целое число) m.lock () callback (i) m.unlock ()функция обратный вызов (я: целое число) если i> 0 lock_and_call (i - 1) lock_and_call (1) // Вызов функции

Учитывая эти определения, вызов функции lock_and_call (1) вызовет следующую последовательность событий:

  • m.lock () - мьютекс заблокирован
  • обратный звонок (1)
  • lock_and_call (0) - потому что я> 0
  • m.lock () - тупик, потому что м уже заблокирован, поэтому выполняющийся поток заблокируется, ожидая самого себя.

Замена мьютекса на рекурсивный решает проблему, потому что последний m.lock () будет успешным без блокировки.

Практическое использование

В. Ричард Стивенс отмечает, что рекурсивные блокировки «сложно» использовать правильно, и рекомендует их использовать для адаптации однопоточного кода без изменения API, но «только тогда, когда другое решение невозможно».[2]

В Ява собственный механизм синхронизации языка, монитор, использует рекурсивные блокировки. Синтаксически блокировка - это блок кода с предшествующим ему ключевым словом synchronized и любым Объект ссылка в скобках, которая будет использоваться в качестве мьютекса. Внутри синхронизированного блока данный объект можно использовать как переменную условия, выполнив для него wait (), notify () или notifyAll (). Таким образом, все объекты являются рекурсивными мьютексами и переменные состояния.[3]

пример

  1. Поток A вызывает функцию F, которая получает повторную блокировку для себя перед продолжением
  2. Поток B вызывает функцию F, которая пытается получить повторно входящую блокировку для себя, но не может из-за того, что одна уже не обработана, что приводит либо к блоку (он ожидает), либо к таймауту, если требуется
  3. Поток A F вызывает себя рекурсивно. Он уже владеет блокировкой, поэтому не будет блокировать себя (без взаимоблокировки). Это основная идея реентерабельного мьютекса, и это то, что отличает его от обычной блокировки.
  4. F потока B все еще ожидает или перехватил тайм-аут и работал над ним.
  5. Нить F завершает работу и снимает блокировку (и)
  6. F потока B теперь может получить реентерабельную блокировку и продолжить, если он все еще ждал

Программная эмуляция

Возможна программная эмуляция[требуется разъяснение ] используя следующую структуру:[нужна цитата ]

  • "Контроль" состояние используя обычный замок
  • Идентификатор владельца, уникальный для каждого потока (по умолчанию пустой / не установлен)
  • Количество приобретений (по умолчанию ноль)

Получение

  1. Получите контрольное условие.
  2. Если установлен владелец, а не текущий поток, дождитесь уведомления условия управления (это также снимает условие).
  3. Установите владельца на текущий поток. Идентификатор владельца уже должен быть очищен на этом этапе, если покупатель уже не является владельцем.
  4. Увеличьте количество приобретений (всегда должно приводить к 1 для новых владельцев).
  5. Отпустите условие управления.

Выпуск

  1. Получите условие управления, утверждая, что владелец является инициатором.
  2. Уменьшите счетчик сбора данных, утверждая, что счет больше или равен нулю.
  3. Если счетчик сбора данных равен нулю, очистите информацию о владельце и сообщите о состоянии управления.
  4. Отпустите условие управления.

использованная литература

  1. ^ Бушманн, Франк; Хенни, Кевлин; Шмидт, Дуглас К. (2007). Шаблонно-ориентированная архитектура программного обеспечения, язык шаблонов для распределенных вычислений. Джон Вили и сыновья. п. 374.
  2. ^ Стивенс, У. Ричард; Раго, Стивен А. (2013). Расширенное программирование в среде UNIX. Эддисон-Уэсли. п. 434.
  3. ^ Дэвид Ховемейер. «Лекция 17: Потоки Java, синхронизация». CS 365 - Параллельные и распределенные вычисления. Конспект лекций, Йоркский колледж Пенсильвании. Получено 4 июн 2015.