Ответ 1
Теория
В теории, когда поток пытается заблокировать мьютекс, и это не удастся, поскольку мьютекс уже заблокирован, он перейдет в спящий режим, немедленно разрешив запуск другого потока. Он будет продолжать спать до тех пор, пока не проснется, что будет иметь место, когда мьютекс будет разблокирован любой нитью, удерживающей замок раньше. Когда поток пытается заблокировать спин-блокировку, и это не удастся, он будет постоянно повторять попытку блокировки, пока это, наконец, не удастся; таким образом, он не позволит другому потоку занять свое место (однако, операционная система будет принудительно переключиться на другой поток, как только квант времени выполнения процессора текущего потока будет превышен).
Проблема
Проблема с мьютексами заключается в том, что включение потоков в режим сна и их повторное пробуждение являются довольно дорогостоящими операциями, им потребуется довольно много инструкций процессора и, следовательно, потребуется некоторое время. Если теперь мьютекс был заблокирован только в течение очень короткого промежутка времени, время, затрачиваемое на то, чтобы положить поток в сон и пробудить его снова, может превысить время, когда поток действительно спал далеко, и это может даже превысить время, в течение которого поток были потрачены впустую постоянным опросом на спинлоке. С другой стороны, опрос на спин-блокировке будет постоянно тратить процессорное время, и если блокировка будет удерживаться в течение более длительного времени, это будет тратить намного больше времени процессора, и было бы намного лучше, если бы поток спал вместо этого.
Решение
Использование штифтов в одноядерной/однопроцессорной системе обычно не имеет смысла, поскольку до тех пор, пока опрос спин-блокировки блокирует единственное доступное ядро ЦП, ни один другой поток не может запускаться, и поскольку ни один другой поток не может работать, блокировка также не будут разблокированы. IOW, спин-блокировка тратит только время процессора на эти системы без реальной выгоды. Если поток был послан на смену, другой поток мог бы запустить сразу, возможно, разблокировав блокировку, а затем разрешив продолжить первый поток, как только он снова проснулся.
В многоядерных/многопроцессорных системах с большим количеством блокировок, которые хранятся в течение очень короткого времени, время, потраченное на то, чтобы постоянно помещать потоки в сон и пробуждать их снова, может заметно снизить производительность во время выполнения. Вместо использования потоковых стекол потоки получают возможность использовать свой полный квант времени выполнения (всегда только блокирование в течение очень короткого периода времени, но затем сразу же продолжают работу), что приводит к значительно большей пропускной способности обработки.
Практика
Так как очень часто программисты не могут заранее знать, будут ли улучшены мьютексы или штифты, например, потому что количество ядер ЦП целевой архитектуры неизвестно), а также не могут операционные системы знать, был ли оптимизирован определенный фрагмент кода для одного -резервуарных или многоядерных средах, большинство систем строго не различают мьютексы и спин-блокировки. Фактически, большинство современных операционных систем имеют гибридные мьютексы и гибридные винтовые блоки. Что это значит?
Гибкий мьютекс ведет себя как спин-блокировка сначала в многоядерной системе. Если поток не может заблокировать мьютекс, он не будет усыпан немедленно, так как мьютекс может быть разблокирован довольно быстро, поэтому вместо этого mutex будет вести себя точно как спин-блокировка. Только если блокировка еще не была получена через определенное количество времени (или повторений или любого другого измерительного фактора), поток действительно усыпан. Если один и тот же код работает в системе с одним ядром, мьютекс не будет вращаться, хотя, как видно выше, это не выгодно.
Гибридная спин-блокировка сначала ведет себя как нормальная спин-блокировка, но для того, чтобы избежать слишком большого количества процессорного времени, она может иметь откатную стратегию. Обычно это не помещает поток в спящий режим (поскольку вы не хотите, чтобы это происходило при использовании спин-блокировки), но он может решить остановить поток (сразу или через определенное время) и разрешить запуск другого потока, тем самым увеличивая шансы на то, что спин-блокировка разблокирована (чистый переключатель потока обычно дешевле, чем тот, который включает в себя перенос потока и повторное пробуждение его позже, хотя и далеко не).
Сводка
Если вы сомневаетесь, используйте мьютексы, они, как правило, лучший выбор, и большинство современных систем позволят им задерживаться в течение короткого промежутка времени, если это кажется полезным. Использование спинлоков иногда может улучшить производительность, но только при определенных условиях и тот факт, что вы сомневаетесь, скорее говорит мне, что вы не работаете над каким-либо проектом в настоящее время, когда спин-блокировка может быть полезной. Вы можете использовать собственный "объект блокировки", который может использовать внутреннюю часть спин-блокировки или мьютекса (например, это поведение можно настроить при создании такого объекта), изначально использовать мьютексы повсюду, и если вы считаете, что использование спин-блокировки где-то может действительно помогите, попробуйте и сравните результаты (например, используя профилировщик), но не забудьте проверить оба случая, одноядерную и многоядерную систему, прежде чем перейти к выводам (и, возможно, к разным операционным системам, если ваш код будет кросс-платформенным).