Наверх Системное программирование
Предыдущий раздел Оглавление Следующий раздел

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, чтобы уступить центральный процессор другому потоку. Следовательно, активное ожидание отсутствует. Когда поток в очередной раз возобновит свою работу, он снова проверяет состояние блокировки.

Предыдущий раздел Оглавление Следующий раздел