Friday, May 18th

Last update12:13:00 PM GMT

Вы находитесь на: FreeBSD Службы ядра Синхронизация с помощью мьютекса

Синхронизация с помощью мьютекса

Мьютексы - это основной способ синхронизации потоков. Главными соображениями в дизайне мьютексов являются следующие.

Получение и освобождение безальтернативных мьютексов должно быть как можно более дешевым.

Мьютексы должны содержать информацию и область памяти для поддержки передачи приоритетов.

Поток должен иметь возможность рекурсивно получать мьютекс, если мьютекс инициализирован с поддержкой рекурсии.

В настоящее время имеются две разновидности мьютексов: ожидающие и неожидающие. По умолчанию мьютексы будут находиться в состоянии сна, если ими уже владеют. В качестве машинно-зависимой оптимизации они могут в течение некоторого времени находиться в цикле до вхождения в состояние сна. Большая часть кода ядра использует тип блокировки по умолчанию; тип блокировки по умолчанию дает потоку возможность отключиться от процессора, если он не может получить блокировку. Машинно-зависимая реализация может при некоторых обстоятельствах рассматривать блокировку как кратковременную циклическую блокировку. Однако всегда безопасно использовать эти формы блокировок в потоке прерывания, не опасаясь тупиков со стороны прерванных потоков на том же самом процессоре. Если некоторый поток прервал другой поток, который владел мьютексом, а затем попытался получить этот мьютекс, он войдет в состояние сна до тех пор, пока поток, удерживающий мьютекс, не отработает до завершения и не освободит мьютекс.

Неожидающие мьютексы называются циклическими мьютексами (spin mutexes).
Циклический мьютекс не освобождает процессор при невозможности немедленно
получить запрошенную блокировку, но будет вращаться в цикле до освобождения
мьютекса другим процессором. Это зацикливание может привести к тупику, если
поток прервал другой поток, который владел мьютексом, а затем попытался получить
этот мьютекс. Чтобы защитить процедуру обслуживания прерывания от самоблокиро-
вания, при удерживании на локальном процессоре циклических блокировок все преры-
вания блокируются. Таким образом, во время владения мьютексом прерывание может
возникнуть лишь на другом процессоре.

Циклические блокировки являются специализированными блокировками, которые предназначены для кратковременного использования; их главным назначением является защита участков кода, которые реализуют блокировки по умолчанию (т. е. ожидающие). Эти мьютексы должны использоваться лишь для защиты данных, совместно используемых любыми Устройствами, которым требуются невытесняющиеся прерывания и низкоуровневый код планирования. На большинстве архитектур как получение, так и освобождение безальтернативных циклических мьютексов дороже, чем та же самая операция с нециклическим мьютексом. Допускается удержание нескольких циклических мьютексов. В этом случае требуется, чтобы они освобождались в обратном по сравнению с получением порядке. Входить в состояние сна, удерживая i циклический мьютекс, не допускается.

Для инициализации мьютекса до передачи его функции mtxJock() должна использоваться функция mtxinit(). Функция mtx_init() указывает тип, который код модуля доказательств использует для классификации мьютексов при осуществлении проверки упорядочения блокировок. Не допускается"*' несколько раз передавать функции mtx_init() один и тот же мьютекс без промежуточных вызовов mtx_destroy().

Функция mtxJock() получает взаимно исключающую блокировку для текущего выполняющегося потока ядра. Если мьютекс удерживается другим потоком ядра, вызывающий войдет в состояние сна до тех пор, пока мьютекс не станет доступным. Функция mtx_lock_spin() сходна с mtxJock(), за тем исключением, что она зациклится до тех пор, пока мьютекс не станет доступным. Прерывания процессора, удерживающего мьютекс, запрещаются на время цикла ожидания и остаются запрещенными после получения блокировки.

Один и тот же поток может рекурсивно получить мьютекс без вредных последствий, если во время инициализации мьютекса функции mtxJnit() будет передан бит MTXRECURSE. Модуль доказательств проверяет, что поток не использует рекурсию с нерекурсивной блокировкой. Рекурсивная блокировка полезна, когда ресурс может быть заблокирован в ядре на двух или более уровнях. Разрешая рекурсивную блокировку, более низкому уровню не нужно проверять, был ли ресурс уже заблокирован более высоким уровнем; он может просто блокировать и освобождать ресурс по мере необходимости.

Функция mtxjrylock() пытается получить взаимоисключающую блокировку для текущего выполняющегося потока ядра. Если мьютекс не может быть получен немедленно, mtxjrylock() вернет 0; в противном случае будет получен мьютекс и возвращено ненулевое значение.

Функция mtxunlock() освобождает взаимоисключающую блокировку; если мьютекс ожидается потоком с более высоким приоритетом, освободивший поток будет помещен в состояние сна, чтобы позволить получить мьютекс и запустить поток с более высоким приоритетом. Мьютекс, допускающий рекурсивное блокирование, содержит счетчик ссылок, который указывает, сколько раз он был заблокирован. Для каждого успешного запроса блокировки должен быть соответствующий запрос освобождения. Мьютекс не освобождается до тех пор, пока не будет выполнен конечный запрос освобождения, обнуляющий счетчик ссылок.

Функция mtx_unlock_spin() освобождает взаимоисключающую циклическую блокировку; состояние прерывания, которое было до получения блокировки, восстанавливается.

Функция mtx_destroy() разрушает мьютекс таким образом, что связанные с ним данные могут быть освобождены или перезаписаны. Каждый разрушаемый мьютекс должен быть предварительно инициализирован с помощью mtxinit(). При разрушении мьютекса допускается иметь на него единственную ссылку. При разрушении мьютекса не допускается его рекурсивное удержание или блокирование на нем другого потока. Если эти правила нарушаются, ядро входит в состояние паники.

Всеобщая блокировка, защищающая подсистемы в FreeBSD 5.2, которые еще не были преобразованы для работы на многопроцессорной системе, должна быть получена до получения других мьютексов. Другими словами, невозможно получить всеобщую блокировку, удерживая другой мьютекс. Можно получить другие мьютексы, удерживая всеобщую, а также можно рекурсивно получать всеобщую блокировку, удерживая другие мьютексы.

Нахождение в состоянии сна с удерживанием мьютекса (за исключением всеобщего) почти никогда не является безопасным и должно избегаться. Имеются многочисленные диагностические проверки, которые потерпят неудачу при такой попытке.


Похожие:
Еще по теме:
Советуем прочитать:

Сейчас 70 гостей онлайн

Реклама на сайте:

http://www.a1card.ru/

саморезы оптом москва

цинкование металла методы и преимущества.