Когда следует использовать спин-блокировку вместо мьютекса?

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

Ответ 1

Теория

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

Проблема

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

Решение

Использование штифтов в одноядерной/однопроцессорной системе обычно не имеет смысла, поскольку до тех пор, пока опрос спин-блокировки блокирует единственное доступное ядро ​​ЦП, ни один другой поток не может запускаться, и поскольку ни один другой поток не может работать, блокировка также не будут разблокированы. IOW, спин-блокировка тратит только время процессора на эти системы без реальной выгоды. Если поток был послан на смену, другой поток мог бы запустить сразу, возможно, разблокировав блокировку, а затем разрешив продолжить первый поток, как только он снова проснулся.

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

Практика

Так как очень часто программисты не могут заранее знать, будут ли улучшены мьютексы или штифты, например, потому что количество ядер ЦП целевой архитектуры неизвестно), а также не могут операционные системы знать, был ли оптимизирован определенный фрагмент кода для одного -резервуарных или многоядерных средах, большинство систем строго не различают мьютексы и спин-блокировки. Фактически, большинство современных операционных систем имеют гибридные мьютексы и гибридные винтовые блоки. Что это значит?

Гибкий мьютекс ведет себя как спин-блокировка сначала в многоядерной системе. Если поток не может заблокировать мьютекс, он не будет усыпан немедленно, так как мьютекс может быть разблокирован довольно быстро, поэтому вместо этого mutex будет вести себя точно как спин-блокировка. Только если блокировка еще не была получена через определенное количество времени (или повторений или любого другого измерительного фактора), поток действительно усыпан. Если один и тот же код работает в системе с одним ядром, мьютекс не будет вращаться, хотя, как видно выше, это не выгодно.

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

Сводка

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

Ответ 2

Продолжая предложение Mecki, эта статья puteread mutex vs pthread spinlock в блоге Александра Сандлера, Алекс на Linux показывает, как spinlock и mutexes может быть реализована для проверки поведения с помощью #ifdef.

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

Ответ 3

Также обратите внимание, что в определенных средах и условиях (например, при запуске на окнах на уровне отправки >= DISPATCH LEVEL) вы не можете использовать мьютекс, а скорее спин-блокировку. На unix - то же самое.

Вот эквивалентный вопрос на сайте unix-сайта конкурента stackexchange: https://unix.stackexchange.com/questions/5107/why-are-spin-locks-good-choices-in-linux-kernel-design-instead-of-something-more

Информация о диспетчеризации систем Windows: http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/IRQL_thread.doc

Ответ 4

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

Ответ 5

Механизмы синхронизации Spinlock и Mutex очень часто встречаются сегодня.

Пусть сначала подумают о Спинлоке.

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

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

В однородных многоядерных средах, если время в критическом разделе меньше, чем использование Spinlock, потому что мы можем уменьшить время переключения контекста. (Одноядерное сравнение не важно, поскольку некоторые системы реализуют Spinlock в середине коммутатора)

В Windows, используя Spinlock, будет обновлен поток до DISPATCH_LEVEL, который в некоторых случаях может быть недопустим, поэтому на этот раз нам пришлось использовать Mutex (APC_LEVEL).

Ответ 6

Использование штифтов в одноядерной/однопроцессорной системе обычно не имеет смысла, поскольку до тех пор, пока опрос спин-блокировки блокирует единственное доступное ядро ​​ЦП, ни один другой поток не может запускаться, и поскольку ни один другой поток не может работать, блокировка также не будут разблокированы. IOW, спин-блокировка отнимает только процессорное время на этих системах без реальной выгоды

Это неправильно. Нет никакого изъятия циклов процессора при использовании шпиндельных блоков в унифицированных процессорных системах, потому что, как только процесс принимает блокировку спина, прерывание отключается, поэтому не может быть никого другого, вращающегося! Это просто, что использование этого не имеет никакого смысла! Следовательно, спин-блокировки на Uni-системах заменяются на preempt_disable во время компиляции ядром!