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

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

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


person iankits    schedule 12.10.2008    source источник


Ответы (11)


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

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

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

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

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

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

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

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

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

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

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

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

person Damon    schedule 20.06.2013
comment
«Кроме того, в одноядерной системе спин-блокировка будет совершенно неэффективной при наличии перегрузки блокировок, поскольку вращающийся поток будет тратить все свое время на ожидание изменения состояния, которое не может произойти»: также (по крайней мере, в Linux ) spin_trylock, который немедленно возвращается с кодом ошибки, если блокировка не может быть получена. Спин‑блокировка не всегда бывает такой жесткой. Но использование spin_trylock требует, чтобы приложение было правильно спроектировано таким образом (вероятно, очередь ожидающих операций, а здесь выбор следующей, оставляя фактическую в очереди). - person Hibou57; 30.07.2013
comment
Блокирующие мьютексы и семафоры полезны не только в однопоточных средах, но также и в случае переподписки, то есть количество потоков, создаваемых программой (или несколькими программами, совместно использующими систему), превышает количество аппаратных ресурсов. В этих случаях блокировка вашего потока позволяет другим использовать процессорное время с пользой. Кроме того, если аппаратное обеспечение поддерживает гиперпоточность, другой поток может использовать исполнительные блоки, используемые для выполнения цикла бездействия. - person Jorge Bellon; 05.01.2017

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

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

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

person gbjbaanb    schedule 12.10.2008

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

person Jonathan Leffler    schedule 12.10.2008
comment
Я хотел бы подчеркнуть, насколько важно не использовать спин-блокировки в однопоточных системах. Они отмечены как проблемы с инверсией приоритета. И поверьте мне: вы не хотите отлаживать такие ошибки. - person Nils Pipenbrinck; 13.10.2008
comment
спин-блокировки присутствуют в ядре Linux повсюду, независимо от того, есть ли у вас один или несколько процессоров. Что ты конкретно имеешь ввиду? - person Prof. Falken; 07.05.2010
comment
@Amigable: по определению спин-блокировка означает, что текущий поток на ЦП ожидает чего-то еще, чтобы освободить заблокированный объект. Если единственной активной вещью, которая может изменить блокировку, является текущий ЦП, блокировка не будет освобождена вращением. Если что-то еще - передача DMA или другой контроллер ввода-вывода может снять блокировку, все в порядке. Но вращение, когда ничто другое не может снять блокировку, не очень разумно - вы можете с таким же успехом уступить ЦП другому процессу сейчас, чем ждать вытеснения. - person Jonathan Leffler; 07.05.2010
comment
Я вполне могу ошибаться, но у меня сложилось впечатление, что ядро ​​Linux с повторным входом (один процессор) может прервать работающую спин-блокировку. - person Prof. Falken; 10.05.2010
comment
@Amigable: есть шанс, что я тоже ошибаюсь, но я думаю, что я близок к классическому определению спин-блокировки. При упреждающем планировании процесс может вращаться в блокировке до конца своего кванта времени или до тех пор, пока прерывание не приведет к его уступке, но если другой процесс должен обеспечить условие, позволяющее заблокировать спин-блокировку, спин-блокировка не является блокировкой. хорошая идея на машине с одним процессором. Система, над которой я работаю, имеет спин-блокировки и настраиваемую верхнюю границу количества вращений, прежде чем она перейдет в режим ожидания без занятости. Это спин-блокировка на уровне пользователя; может быть разница в ядре. - person Jonathan Leffler; 10.05.2010
comment
Извините, я понизил ваш ответ - хотя спин-блокировки часто могут быть не очень хорошей идеей с точки зрения производительности, почти любая известная мне современная система (будь то однопроцессорная или многопроцессорная, серверная или встроенная) использует какую-то некооперативную многозадачность, где задача блокировки не должна выполняться вручную. Таким образом, общее утверждение о том, что спин-блокировки нельзя использовать на однопроцессорных процессорах, просто неверно. - person MikeMB; 26.03.2015
comment
@MikeMB: Где я сказал, что спин-блокировка не может использоваться на отдельных процессорах? Я говорю вам, что вы никогда не будете использовать спин-блокировку на машине с одним процессором (обратите внимание, что бы сильно отличалось от может!) и описать, что произойдет, если вы это сделаете (если один ЦП занят ожиданием чего-то еще, чтобы освободить спин). -lock, но он работает на единственном процессоре, блокировка вряд ли будет снята). Возможно, мне следует добавить до тех пор, пока текущий процесс или поток не будут вытеснены, но главное остается: если вы используете спин-блокировку на машине с одним процессором, ваш процесс может долгое время вращаться на блокировке. - person Jonathan Leffler; 26.03.2015
comment
Вы пишете, но в обстоятельствах, когда у вас есть только один ЦП, вы ДОЛЖНЫ использовать семафоры. Если вы удалите обязательность и добавите предложенную вами заметку, я с радостью уберу свой отрицательный голос. Кроме того, я не уверен, что это по-прежнему считается спин-блокировкой, но я видел реализации, которые вызывают yield до того, как они попытаются снова получить блокировку. Я полностью согласен с тем, что обычно это не очень хорошая идея. - person MikeMB; 26.03.2015
comment
@MikeMB: я пересмотрел ответ, чтобы охватить вопросы, которые мы обсуждали, которые также в значительной степени освещены в комментариях прошлых лет. - person Jonathan Leffler; 26.03.2015

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

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

person Zbyszek    schedule 17.11.2011

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

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

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

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

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

person Raman Chalotra    schedule 21.06.2010

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

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

Тем не менее, реализация splinlocks в сборке сложна и не переносима.

person yoav.aviram    schedule 12.10.2008
comment
Все многопоточные ЦП нуждаются в инструкции спин-блокировки (проверить и установить), и она всегда реализуется как одна инструкция на аппаратном уровне, потому что в противном случае всегда возникало бы состояние гонки, в котором более чем один поток думал, что он владеет защищенным ресурсом. - person Richard T; 12.10.2008
comment
Я не уверен, что вы понимаете семафоры... посмотрите, что сказал Дийкстра: cs.cf.ac.uk/Дэйв/C/node26.html - person gbjbaanb; 12.10.2008
comment
POSIX делает различие между семафором, используемым потоками, и семафором, используемым процессами. - person Greg Rogers; 13.10.2008
comment
Семафоры предназначены для межпроцессной синхронизации, а не для связи. - person Johan Bezem; 15.11.2011

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

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

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

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

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

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

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

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

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

person Johan Bezem    schedule 15.11.2011

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

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

person Community    schedule 21.05.2012

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

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

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

person sukumarst    schedule 21.06.2013

Из в чем разница между спин-блокировками и семафоры? автор Мацей Пехотка:

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

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

while (try_acquire_resource ()); 
 ...  
release();

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

if (!try_lock()) {
    add_to_waiting_queue ();
    wait();
}
...
process *p = get_next_process_from_waiting_queue ();
p->wakeUp ();

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

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

P(resources_sem)
resource = resources.pop()
...
resources.push(resources)
V(resources_sem)

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

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

person vinayak jadi    schedule 24.06.2013
comment
Кажется, это копия/вставка этого ;-): в чем разница между спин-блокировками и семафорами? - person Hibou57; 30.07.2013

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

person sanket31    schedule 15.05.2019