Предыдущий раздел | Оглавление | Следующий раздел |
3.3.5. Мьютексы
Иногда при невостребованности возможностей семафоров в качестве счетчиков используется их упрощенная версия, называемая мьютексом. Мьютексы справляются лишь с управлением взаимным исключением доступа к общим ресурсам или фрагментам кода. Простота и эффективность реализации мьютексов делает их особенно полезными для совокупности потоков, целиком реализованных в пользовательском пространстве.
Мьютекс — это совместно используемая переменная, которая может находиться в одном из двух состояний: заблокированном или незаблокированном. Следовательно, для их представления нужен только один бит, но на практике зачастую используется целое число, при этом нуль означает незаблокированное, а все остальные значения — заблокированное состояние. Для работы с мьютексами используются две процедуры. Когда потоку (или процессу) необходим доступ к критической области, он вызывает процедуру mutex_lock. Если мьютекс находится в незаблокированном состоянии (означающем доступность входа в критическую область), вызов проходит удачно и вызывающий поток может свободно войти в критическую область.
В то же время, если мьютекс уже заблокирован, вызывающий поток блокируется до тех пор, пока поток, находящийся в критической области, не завершит свою работу и не вызовет процедуру mutex_unlock. Если на мьютексе заблокировано несколько потоков, то произвольно выбирается один из них, которому разрешается воспользоваться заблокированностью других потоков.
В листинге 3.3 показан код процедур mutex_lock и mutex_unlock, предназначенных для использования в совокупности потоков, работающих в пользовательском пространстве.
Листинг 3.3.Реализация mutexjock и mutex_unlock mutex_lock:
TSL REGISTER,MUTEX | копирование мьютекса в регистр и установка его в 1 CMP REGISTER,#0 | был ли мьютекс нулевым? JZE ok | если он был нулевым, значит, не был заблокирован,поэтому | нужно вернуть управление вызывающей программе CALL thread_yield | мьютекс занят; пусть планировщик возобновит работу другого потока JMP mutex lock | повторная попытка ok: RET | возврат управления вызывающей программе; |будет осуществлен вход в критическую область mutex_unlock: MOVE MUTEX,#0 | сохранение в мьютексе значения 0 RET | возврат управления вызывающей программе
Код процедуры mutex_lock похож на код enter_region в листинге 3.1, но с одной существенной разницей. Когда процедуре enter_region не удается войти в критическую область, она продолжает повторное тестирование значения переменной lock (выполняет активное ожидание). По истечении определенного времени планировщик возобновляет работу какого-нибудь другого процесса. Рано или поздно возобновляется работа процесса, удерживающего блокировку, и он ее освобождает.
При работе с потоками (в пользовательском пространстве) складывается несколько иная ситуация, связанная с отсутствием таймера, останавливающего работу слишком долго выполняющегося процесса. Следовательно, поток, пытающийся воспользоваться блокировкой, находясь в состоянии активного ожидания, войдет в бесконечный цикл и никогда не завладеет блокировкой, поскольку он никогда не позволит никакому другому потоку возобновить выполнение и снять блокировку.
Вот в этом и заключается разница между enter_region и mutex_lock. Когда последняя из этих процедур не может завладеть блокировкой, она вызывает процедуру thread_ yield, чтобы уступить центральный процессор другому потоку. Следовательно, активное ожидание отсутствует. Когда поток в очередной раз возобновит свою работу, он снова проверяет состояние блокировки.
Предыдущий раздел | Оглавление | Следующий раздел |