Спинлок против семафора

119

Каковы основные различия между семафором и спин-блокировкой?

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

iankits
источник

Ответы:

134

Спинлок и семафор различаются в основном четырьмя вещами:

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

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

В этом случае блокировку можно рассматривать как частный случай семафора с максимальным значением 1.

2. Что они делают
Как было сказано выше, спин-блокировка - это механизм блокировки и, следовательно, механизм взаимного исключения (строго 1 к 1). Он работает путем многократных запросов и / или изменения области памяти, обычно атомарно. Это означает, что получение спин-блокировки является «занятой» операцией, которая, возможно, сжигает циклы ЦП на долгое время (возможно, навсегда!), В то время как фактически «ничего» не достигает.
Основным стимулом для такого подхода является тот факт, что переключение контекста имеет накладные расходы, эквивалентные вращению несколько сотен (или, возможно, тысяч) раз, поэтому, если блокировка может быть получена путем сжигания нескольких циклов вращения, в целом это вполне может быть более эффективным. Кроме того, для приложений реального времени может оказаться неприемлемым блокировка и ожидание, пока планировщик вернется к ним в какое-то отдаленное время в будущем.

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

3. Как они ведут себя в условиях перегрузки.
Распространенное заблуждение состоит в том, что спин-блокировки или алгоритмы без блокировок «в целом быстрее» или что они полезны только для «очень коротких задач» (в идеале ни один объект синхронизации не должен удерживаться дольше чем абсолютно необходимо, когда-либо).
Одно важное различие заключается в том, как разные подходы ведут себя в условиях перегрузки .

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

В таком случае спин-блокировка значительно превосходит семафор, потому что, если нет перегрузки блокировки, накладные расходы на получение спин-блокировки составляют всего лишь десяток циклов по сравнению с сотнями / тысячами циклов для переключения контекста или 10-20 миллионов циклов для потери. оставшаяся часть временного интервала.

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

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

4. Как они реализованы.
В настоящее время семафор обычно оборачивается sys_futexв Linux (опционально со спин-блокировкой, которая выходит после нескольких попыток).
Спин-блокировка обычно реализуется с использованием атомарных операций и без использования чего-либо, предоставляемого операционной системой. В прошлом это означало использование встроенных функций компилятора или непереносимых инструкций ассемблера. Между тем и C ++ 11, и C11 имеют атомарные операции как часть языка, поэтому, помимо общей сложности написания доказуемо правильного кода без блокировки, теперь можно реализовать код без блокировки в полностью переносимом и (почти) безболезненный способ.

Damon
источник
«Кроме того, в одноядерной системе спин-блокировка будет довольно неэффективной при наличии перегрузки блокировок, поскольку вращающийся поток будет тратить свое полное время на ожидание изменения состояния, которое, возможно, не может произойти»: также существует (по крайней мере, в Linux ) spin_trylock, который немедленно возвращается с кодом ошибки, если блокировку не удалось получить. Спин-блокировка не всегда такая резкая. Но для использования spin_trylockтребуется, чтобы приложение было правильно спроектировано таким образом (возможно, очередь ожидающих операций, а здесь, выбор следующей, оставление фактических в очереди).
Hibou57
Блокирующие мьютексы и семафоры полезны не только в однопоточных средах, но и при превышении лимита подписки, т. Е. Количество потоков, создаваемых программой (или несколькими программами, совместно использующими систему), превышает количество аппаратных ресурсов. В этих случаях блокировка вашего потока позволяет другим использовать время процессора с пользой. Кроме того, если оборудование поддерживает гиперпоточность, другой поток может использовать исполнительные блоки, которые используются для выполнения цикла ожидания.
Хорхе Беллон
76

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

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

обычно, если вы вращаетесь дольше кванта потока, вам следует использовать семафор.

gbjbaanb
источник
27

Помимо того, что сказали Йоав Авирам и gbjbaanb, другим ключевым моментом было то, что вы никогда не будете использовать спин-блокировку на однопроцессорной машине, тогда как семафор имеет смысл на такой машине. В настоящее время вам часто бывает трудно найти машину без нескольких ядер, гиперпоточности или эквивалента, но в обстоятельствах, когда у вас всего один процессор, вам следует использовать семафоры. (Я верю, что причина очевидна. Если один ЦП занят ожиданием чего-то еще, чтобы освободить спин-блокировку, но он работает на единственном ЦП, блокировка вряд ли будет снята, пока текущий процесс или поток не будет вытеснен O / S, что может занять некоторое время и ничего полезного не произойдет, пока не произойдет приоритетное прерывание.)

Джонатан Леффлер
источник
7
Я хотел бы отметить, насколько важно не использовать спин-блокировки в однопоточных системах. Это проблемы с инверсией приоритета. И поверьте мне: вы не хотите отлаживать такого рода ошибки.
Нильс Пипенбринк,
2
спин-блокировки полностью отсутствуют в ядре Linux, независимо от того, есть ли у вас один или несколько процессоров. Что ты конкретно имеешь ввиду?
Проф. Фалькен
@Amigable: по определению спин-блокировка означает, что текущий поток на ЦП ожидает чего-то еще, чтобы освободить заблокированный объект. Если единственным активным элементом, который может изменить блокировку, является текущий процессор, блокировка не будет освобождена путем вращения. Если что-то еще - передача DMA или другой контроллер ввода-вывода может снять блокировку, все хорошо. Но вращение, когда ничто другое не может освободить блокировку, не очень разумно - вы могли бы с таким же успехом передать ЦП другому процессу сейчас, чем ждать, пока его вытеснят.
Джонатан Леффлер,
1
Возможно, я ошибаюсь, но у меня создалось впечатление, что реентерабельное (однопроцессорное) ядро ​​Linux может прервать текущую блокировку вращения.
Проф. Фалькен
2
@Amigable: есть шанс, что я тоже ошибаюсь, но мне кажется, что я близок к классическому определению спин-блокировки. При упреждающем планировании процесс может вращаться на блокировке до конца своего временного отрезка или до тех пор, пока прерывание не приведет к его срабатыванию, но если другой процесс должен обеспечить условие, позволяющее блокировать спин-блокировку, спин-блокировка не является хорошая идея на машине с одним процессором. Система, над которой я работаю, имеет спин-блокировки и настраиваемую верхнюю границу количества вращений, прежде чем она перейдет в режим ожидания без занятости. Это спин-блокировка на уровне пользователя; может быть разница в ядре.
Джонатан Леффлер
19

Из драйверов устройств Linux от Rubinni

В отличие от семафоров, спин-блокировки могут использоваться в коде, который не может спать, например в обработчиках прерываний.

Zbyszek
источник
8

Я не эксперт по ядру, но вот несколько моментов:

Даже однопроцессорная машина может использовать спин-блокировки, если во время компиляции ядра включено вытеснение ядра. Если вытеснение ядра отключено, то спин-блокировка (возможно) заменяется оператором void .

Кроме того, когда мы пытаемся сравнить семафор и спин-блокировку, я считаю, что семафор относится к тому, который используется в ядре, а НЕ к тому, который используется для IPC (пользовательское пространство).

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

Раман Чалотра.

Раман Чалотра
источник
7

Spinlock относится к реализации межпотоковой блокировки с использованием машинно-зависимых инструкций сборки (таких как test-and-set). Это называется спин-блокировкой, потому что поток просто ждет в цикле («вращается»), многократно проверяя, пока блокировка не станет доступной (ожидание занятости). Спин-блокировки используются в качестве замены мьютексов, которые являются средством, предоставляемым операционными системами (а не ЦП), потому что спин-блокировки работают лучше, если они заблокированы на короткий период времени.

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

Тем не менее, установка шпонок при сборке - дело сложное и непростое.

yoav.aviram
источник
4
Всем многопоточным процессорам нужна инструкция спин-блокировки («тест и установка»), и она всегда реализуется как одна инструкция на оборудовании, потому что в противном случае всегда было бы состояние гонки, в котором более чем один поток считал, что он «владеет» защищенным ресурсом.
Ричард Т
Я не уверен, что вы понимаете семафоры ... посмотрите, что сказал Дийкстра
gbjbaanb
POSIX делает различие между семафором, совместно используемым потоками, и семафором, совместно используемым процессами.
Грег Роджерс,
2
Семафоры предназначены для межпроцессной синхронизации, а не для связи.
Йохан Безем
6

Я хотел бы добавить свои наблюдения, более общие и не очень специфичные для Linux.

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

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

Однако, поскольку спроектированы простые / дешевые многоядерные системы (я работаю со встроенными системами), не все архитектуры памяти поддерживают такие многоядерные / многопроцессорные функции, только test-and-set или эквивалентные. Тогда реализация могла бы быть такой:

  • получить спин-блокировку (занятое ожидание)
  • попытаться получить семафор
  • отпустить спин-блокировку
  • если семафор не был успешно получен, приостановить текущий поток, пока семафор не будет освобожден; в противном случае перейдите к критическому разделу

Освобождение семафора должно быть реализовано следующим образом:

  • получить спин-блокировку
  • отпустить семафор
  • отпустить спин-блокировку

Да, и для простых двоичных семафоров на уровне ОС можно было бы использовать только спин-блокировку в качестве замены. Но только если защищаемые участки кода действительно очень маленькие.

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

Йохан Безем
источник
1

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

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


источник
1

Spinlock используется тогда и только тогда, когда вы уверены, что ожидаемый результат произойдет очень скоро, до истечения времени среза выполнения вашего потока.

Пример: В модуле драйвера устройства драйвер записывает «0» в аппаратный регистр R0, и теперь ему нужно дождаться, пока этот регистр R0 станет 1. H / W читает R0, выполняет некоторую работу и записывает «1» в R0. Обычно это происходит быстро (за микросекунды). Теперь крутиться намного лучше, чем ложиться спать и прерывать H / W. Конечно, во время отжима необходимо следить за состоянием отказа H / W!

Нет абсолютно никаких причин для вращения пользовательского приложения. В этом нет смысла. Вы собираетесь вращаться, чтобы произошло какое-то событие, и это событие должно быть завершено другим приложением уровня пользователя, что никогда не может быть гарантировано в короткие сроки. Так что в пользовательском режиме крутить вообще не буду. Мне лучше sleep () или mutexlock () или semaphore lock () в пользовательском режиме.

sukumarst
источник
1

В чем разница между спин-блокировками и семафорами? от Maciej Piechotka :

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

Спиновые блокировки выполняют ожидание занятости - т.е. цикл продолжается:

пока (try_acquire_resource ()); 
 ...  
релиз();

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

if (! try_lock ()) {
    add_to_waiting_queue ();
    Подождите();
}
...
процесс * p = get_next_process_from_waiting_queue ();
p-> wakeUp ();

Следовательно, если поток попытается получить заблокированный ресурс, он будет приостановлен до тех пор, пока он не станет для него доступным. Блокировка / разблокировка намного сложнее, но ожидание «бесплатное» и «справедливое».

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

Р (resources_sem)
resource = resources.pop ()
...
resources.push (ресурсы)
В (resources_sem)

Разница между семафором, мьютексом и спин-блокировкой?

Блокировка в Linux

Винаяк Джади
источник
1
Кажется, это копия / вставка этого ;-): в чем разница между спин-блокировками и семафорами?
Hibou57,
0

Блокировка спина может удерживаться только одним процессом, а семафор может удерживаться одним или несколькими процессами. Спин-блокировка ожидает, пока процесс снимет блокировку, а затем получит блокировку. Семафор находится в режиме ожидания, т.е. ждет и засыпает.

sanket31
источник