Почему большинство реализаций мьютекса несправедливы?


11

Насколько я понимаю, большинство популярных реализаций мьютекса (например, std :: mutex в C ++) не гарантируют справедливости, то есть они не гарантируют, что в случаях конфликта блокировка будет получена потоками в том порядке, в котором они называется блокировка (). На самом деле, даже возможно (хотя мы надеемся, что это необычно), что в случаях высокой конкуренции некоторые потоки, ожидающие получения мьютекса, могут никогда не получить его.

Мне кажется, что это бесполезное поведение - мне кажется, что справедливый мьютекс приведет к тому, что поведение будет в большей степени соответствовать ожиданиям / ожиданиям программиста.

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

Какое понимание реализации мьютекса я здесь упускаю, что объясняет, почему считалось целесообразным пожертвовать честностью ради лучшей производительности?


1
Этот связанный список для каждого мьютекса должен быть общей структурой данных, верно? Итак, как вы собираетесь предотвратить скачки данных без снижения производительности?
user3543290

Я думаю, что с помощью механизма связанного списка без блокировки. Какую структуру данных использует несправедливый мьютекс, чтобы найти следующий поток для пробуждения?
Джереми

1
Вам нужно будет это найти, но гарантирует ли связанный список без блокировки честность? Я думаю, вы обнаружите, что такие гарантии, как честность в параллельном программировании, трудно найти.
user3543290

Ответы:


7

Ответ Джима Сойера указывает на один ответ: если у вас есть темы с разными приоритетами, «честное» поведение будет некорректным. Когда у вас есть несколько потоков, которые могут работать, поток с наивысшим приоритетом, как правило, должен выполняться.

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

Типичным примером является обработчик сигналов в Unix, асинхронная системная ловушка в VMS или асинхронный вызов процедуры в Windows NT. Все это, по сути, одно и то же: операционная система должна уведомить пользовательский процесс о том, что произошло какое-то событие, и это обрабатывается запуском кода в пространстве пользователя.

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

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


4

«Инверсия приоритетов» является одной из причин того, что справедливость может быть нежелательной. Процесс с низким приоритетом попадает в заблокированный мьютекс и спит. Затем процесс с более высоким приоритетом поражает его, а также спит. Когда мьютекс разблокируется, какой процесс должен получить блокировку следующим?


Добро пожаловать на сайт и спасибо за ответ на вопрос, который сидел некоторое время без ответов! Ваш ответ, конечно, правильный, но я чувствую, что он может быть немного более подробным.
Дэвид Ричерби,

3

Справедливый мьютекс потратит больше своей жизни заблокированной, чем несправедливый мьютекс, при прочих равных условиях. Потому что поток, освобождающий несправедливый мьютекс, всегда может просто разблокировать его. Но поток, освобождающий справедливый мьютекс, может разблокировать его, только когда очередь официантов пуста. В противном случае освобождающий поток должен оставить мьютекс заблокированным для следующего потока, то есть первого потока в очереди официантов, который затем отключается и активируется. Мьютекс остается заблокированным, по крайней мере, до тех пор, пока новый пробужденный поток не будет запланирован на ЦП, что может занять много времени, если в настоящий момент имеется много работающих потоков.

И если освобождающий поток немедленно пытается повторно получить тот же мьютекс, он должен поместить себя в заднюю часть очереди официанта и перейти в режим сна. Этого бы не произошло, если бы поток не освободил мьютекс для начала. Поэтому это стимулирует более длинные «более жадные» критические секции.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.