Спінлок проти Семафору


119

Які основні відмінності між семафором та спин-замком?

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

Відповіді:


134

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

1. Що вони спінлкі це одна з можливих реалізацій замку, а саме той , який реалізується зайнятому очікування ( «спінінг»). Семафор - це узагальнення замку (або, навпаки, замок - це особливий випадок семафору). Зазвичай, але необов'язково , спінокси дійсні лише в межах одного процесу, тоді як семафори можуть використовуватися і для синхронізації між різними процесами.

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

Наскільки замок можна вважати особливим випадком семафору з максимальним значенням 1.

2. Що вони роблять
Як зазначено вище, спінінг - це замок, а отже, механізм взаємного виключення (строго від 1 до 1). Він працює шляхом багаторазового запиту та / або зміни місця пам'яті, як правило, атомним способом. Це означає, що придбання спінклока - це "зайнята" операція, яка, можливо, спалює цикли процесора протягом тривалого часу (можливо, назавжди!), А при цьому ефективно не досягає "нічого".
Основним стимулом для такого підходу є той факт, що контекстний перемикач має накладні витрати, еквівалентні обертанню в кілька сотень (а може, і тисячі) разів, тому, якщо блокування можна придбати спаленням декількох циклів, що обертається, це, як правило, може бути дуже добре більш ефективний. Крім того, для додатків у реальному часі може бути неприйнятним блокувати та чекати, коли планувальник повернеться до них у якийсь далекий час у майбутньому.

Навпаки, семафор або взагалі не крутиться, або крутиться дуже короткий час (як оптимізація, щоб уникнути накладних сис-калів). Якщо семафор неможливо придбати, він блокує, відмовляючи час процесора на інший потік, який готовий запустити. Це, звичайно, може означати, що ще кілька мілісекунд пройде до того, як ваш потік буде запланований знову, але якщо це не проблема (зазвичай це не так), це може бути дуже ефективним, консервативним процесором підходом.

3. Як вони поводяться за наявності перевантаженості
Поширене помилкове уявлення про те, що спінкі або алгоритми без блокування є "загалом швидшими", або що вони корисні лише для "дуже коротких завдань" (в ідеалі жоден об'єкт синхронізації не повинен утримуватися довше ніж абсолютно необхідне, ніколи).
Важливою відмінністю є те, як різні підходи поводяться при наявності заторів .

Добре розроблена система зазвичай має низьку або відсутність перевантаженості (це означає, що не всі нитки намагаються придбати замок точно в той самий час). Наприклад, зазвичай не записується код, який набуває блокування, а потім завантажується з мережі половину мегабайт стиснених на блискавці даних, декодує та аналізує дані, і, нарешті, змінює спільну посилання (додавання даних до контейнера тощо). перед тим як звільнити замок. Натомість замок можна придбати лише з метою доступу до спільного ресурсу .
Оскільки це означає, що за межами критичного перерізу значно більше роботи, ніж всередині нього, природно ймовірність того, що нитка знаходиться в критичній секції, є відносно низькою, і, отже, мало ниток претендує на замок одночасно. Звичайно, раз у раз дві нитки намагатимуться придбати замок одночасно (якщо цього не вдалося , вам не знадобиться блокування!), Але це скоріше виняток, ніж правило у «здоровій» системі .

У такому випадку спінінг значно перевершує семафор, оскільки якщо не виникає перевантажених заторів, то накладні витрати на придбання спинлок - це лише десяток циклів порівняно з сотнями / тисячами циклів для контекстного вимикача або 10-20 мільйонів циклів втрати залишок часового фрагмента.

З іншого боку, за умови великої перевантаженості або якщо блокування тримається тривалий час (іноді ви просто не зможете допомогти цьому!), Спінлок буде спалювати шалені кількості циклів процесора, нічого не досягнувши.
Семафор (або мютекс) є набагато кращим вибором у цьому випадку, оскільки він дозволяє іншим потокам виконувати корисні завдання за цей час. Або, якщо жоден інший потік не має чогось корисного зробити, це дозволяє операційній системі знизити процесор і зменшити тепло / економію енергії.

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

4. Як вони реалізовані
. Семафор сьогодні зазвичай завершується sys_futexпід Linux (необов'язково зі спінклоком, який виходить після кількох спроб).
Заключення зазвичай реалізується за допомогою атомних операцій і без використання нічого передбаченого операційною системою. У минулому це означало використання або компіляторних вбудованих даних, або не портативних інструкцій асемблера. Тим часом як C ++ 11, так і C11 є атомними операціями як частиною мови, тому, крім загальної складності написання доказувально правильного коду без замків, тепер можна реалізувати код без замків у повністю портативному та (майже) безболісний спосіб.


"Крім того, для одноядерної системи спінлок буде досить неефективним при наявності перевантаженості блокування, оскільки прядильна нитка витратить весь свій час на очікування зміни стану, яка не може статися": також є (принаймні, в Linux ) spin_trylock, що повертається негайно з кодом помилки, якщо блокування не вдалося отримати. Замикання не завжди є суворим. Але використання програми spin_trylockвимагає, щоб програма була належним чином спроектована таким чином (можливо, чергові операції, що очікують на розгляд, і тут, вибір наступної, залишаючи фактичну в черзі).
Hibou57

Блокування мутексів і семафорів корисно не тільки в однопотокових середовищах, але і при надмірній підписці, тобто кількість потоків, створених програмою (або декількома програмами, що діляться системою), перевищує кількість апаратних ресурсів. У цих випадках блокування потоку дозволяє іншим користувачеві корисно використовувати час процесора. Крім того, якщо апаратне забезпечення підтримує гіперточення, інший потік може використати одиниці виконання, які використовуються для виконання циклу очікування.
Хорхе Беллон

76

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

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

як правило, якщо ви крутитеся довше, ніж квантовий потік, тоді вам слід використовувати семафор.


27

Окрім того, що сказали Yoav Aviram та gbjbaanb, другим ключовим моментом було те, що ви ніколи не використовуватимете замикання на одній процесорній машині, тоді як семафор має сенс на такій машині. Сьогодні у вас часто буває важко знайти машину без декількох ядер, або гіперточення, або еквівалент, але за обставин, що у вас є лише один процесор, вам слід використовувати семафори. (Я вірю, що причина очевидна. Якщо єдиний процесор зайнятий в очікуванні чогось іншого, щоб випустити спін-блокування, але він працює на єдиному процесорі, блокування навряд чи буде випущено, поки поточний процес або потік не буде попереджено O / S, що може зайняти деякий час, і нічого корисного не відбудеться, поки не відбудеться преференція.)


7
Мені хотілося б по-друге, як важливо не використовувати спілок на однопотокових системах. Вони відзначені пріоритетними проблемами з інверсією. І повірте: ви не хочете налагоджувати подібні помилки.
Нільс Піпенбрінк

2
спінлок є в ядрі Linux, незалежно від того, чи є у вас більше одного процесора. Що саме ви маєте на увазі?
Проф. Фолкен

@Amigable: за визначенням, спінлок означає, що поточний потік процесора чекає ще чогось, щоб звільнити заблокований об'єкт. Якщо єдиний активний предмет, який може змінити блокування, - це поточний процесор, блокування не буде звільнено за допомогою спінінгу. Якщо щось інше - передавач DMA або інший контролер вводу / виводу може звільнити замок, все добре і добре. Але обертання, коли ніщо інше не може випустити блокування, не дуже розумне - ви також можете перенести процесор на інший процес зараз, як чекати, щоб його вилучили.
Джонатан Леффлер

1
Можливо, я дуже помиляюся, але в мене склалося враження, що ядро ​​Linux, що повторно вступає (єдиний процесор), може перервати запущений замок спина.
Проф. Фолкен

2
@Amigable: є ймовірність, що я теж помиляюся, але я думаю, що я близький до класичного визначення вертушки. При попередньому плануванні процес може обертатися на блокування до кінця відрізка часу або до того, як переривання призведе до його поступання, але якщо інший процес повинен забезпечити умову, яка дозволяє блокувати спінлок, фіксація не є гарна ідея на одній машині процесора. Система, над якою я працюю, має відмотки і має налаштовану верхню межу кількості спинів, перш ніж вона перейде в режим не зайнятого очікування. Це замок на рівні користувача; може бути різниця в ядрі.
Джонатан Леффлер

19

З драйверів пристроїв Linux від Rubinni

На відміну від семафорів, спінкі можуть використовуватися в коді, який не може заснути, наприклад, обробники переривань


8

Я не знавець ядра, але ось кілька моментів:

Навіть однопроцесорна машина може використовувати спін-блокування, якщо включено попередження ядра під час компілювання ядра. Якщо попередження про ядро ​​вимкнено, то spin-lock (можливо) розширюється до недійсного твердження.

Крім того, коли ми намагаємося порівняти Semaphore з Spin-lock, я вважаю, що семафор відноситься до того, який використовується в ядрі, а не до того, який використовується для IPC (userland).

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

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


7

Spinlock відноситься до реалізації блокування між потоками з використанням інструкцій, що залежать від машини (наприклад, тестування та встановлення). Його називають спінлок, тому що нитка просто чекає в циклі ("крутиться"), повторно перевіряючи, поки замок не стане доступним (зайняте очікування). Spinlocks використовуються в якості заміни для мьютексів, які є засобом, що постачається операційними системами (а не процесором), тому що спінкі є кращими, якщо заблоковані на короткий проміжок часу.

Semaphor є засобом, що постачається операційними системами для IPC, тому його основною метою є міжпроцесовий зв'язок. Будучи об'єктом, що постачається операційною системою, його продуктивність буде не настільки хорошою, як у спінлок для блокування між тезами (хоча це можливо). Семафори краще для фіксації на довші періоди часу.

Однак, сказати, що реалізація сплайнінгу в зборі складна, і не є портативною.


4
Всі багатопотокові процесори потребують інструкції на спінлок ("тест і встановити"), і вона завжди реалізується як одна інструкція з обладнання, оскільки в іншому випадку завжди буде гоночна умова, в якій більше одного потоку вважають, що "володіє" захищеним ресурсом.
Річард Т

Я не впевнений, що ви розумієте семафори ... дивіться, що сказав Dijkstra: cs.cf.ac.uk/Dave/C/node26.html
gbjbaanb

POSIX робить різницю між семафором, який поділяється потоками, і семафором, який поділяється процесами.
Грег Роджерс

2
Семафори - це міжпроцесова синхронізація, а не комунікація.
Йохан Безем

6

Я хотів би додати свої спостереження, більш загальні та не дуже специфічні для Linux.

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

Так, якщо ваша архітектура пам’яті пропонує блокування розділу пам'яті одним ядром / процесором, затримуючи всі інші доступи, а якщо ваші процесори пропонують тест-набір, ви можете реалізувати семафор без спин-блокування (але дуже обережно! ).

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

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

Звільнення семафору потрібно здійснити так:

  • придбати спін-замок
  • випустити семафор
  • відпустіть спін-замок

Так, і для простих бінарних семафорів на рівні ОС можна було б використовувати лише замінник із закруткою. Але лише в тому випадку, якщо розділи коду, які потрібно захистити, насправді дуже малі.

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


1

"Мутекс" (або "блокування взаємного виключення") - це сигнал, який два або більше асинхронних процесів можуть використовувати для резервування спільного ресурсу для виключного використання. Перший процес, який отримує право власності на "mutex", також отримує право власності на спільний ресурс. Інші процеси повинні дочекатися, коли перший процес звільнить його право власності на "мутекс", перш ніж вони можуть спробувати його отримати.

Найпоширеніший примитив блокування в ядрі - це спінлок. Спінлок - це дуже простий замок з одним держателем. Якщо процес намагається придбати спінлок, і він недоступний, процес триватиме спроби (спінінг), поки він не зможе придбати замок. Ця простота створює невеликий і швидкий замок.


1

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

Приклад: У модулі драйвера пристрою драйвер записує "0" в апаратному регістрі R0, і тепер йому потрібно дочекатися, коли цей регістр R0 стане 1. H / W зчитує R0 і виконує певну роботу і записує "1" в R0. Зазвичай це швидко (за мікро секунди). Зараз крутитися набагато краще, ніж лягати спати і перебиватись Ч / З. Звичайно, під час обертання потрібно дотримуватися умови відмови Ч / З!

Немає абсолютно ніяких причин для того, щоб користувальницька програма крутилася. Це не має сенсу. Ви збираєтеся обертатися, щоб відбулася якась подія, і цю подію потрібно заповнити іншою програмою на рівні користувача, яка ніколи не гарантовано відбудеться в швидкі часові рамки. Отже, я взагалі не буду крутитися в режимі користувача. Я краще спати () або mutexlock () або семафорний замок () в режимі користувача.


1

Від чого різниця між прядильними замками та семафорами? автор Мацей П'єхотка :

Обидва керують обмеженим ресурсом. Спершу я опишу різницю між бінарним семафором (мютекс) та фіксацією спіна.

Замкові замки виконують зайняте очікування - тобто він продовжує працювати циклом:

while (try_acquire_resource ()); 
 ...  
випустити ();

Він виконує дуже легке блокування / розблокування, але якщо заблокуючий потік буде випущений іншим, який спробує отримати доступ до того ж ресурсу, другий просто спробує придбати ресурс, поки у нього не вичерпаються квантові процесора.
З іншого боку, мютекс поводиться більше як:

if (! try_lock ()) {
    add_to_waiting_queue ();
    почекати ();
}
...
обробити * p = get_next_process_from_waiting_queue ();
p-> wakeUp ();

Отже, якщо нитка спробує придбати заблокований ресурс, вона буде призупинена, поки не стане для неї доступною. Блокування / розблокування набагато важче, але очікування "вільне" та "справедливе".

Semaphore - це замок, який дозволено використовувати декілька разів (відомий з ініціалізації) - наприклад, 3 потоки дозволяють одночасно утримувати ресурс, але не більше. Він використовується, наприклад, у проблемі виробника / споживача або загалом у чергах:

P (ресурси_sem)
resource = resources.pop ()
...
resource.push (ресурси)
V (ресурси_sem)

Різниця між семафором, мютекс та спінлок?

Блокування в Linux


1
Здається, це копія / вставка цього ;-): у чому різниця між спіновими замками та семафорами?
Hibou57

0

віджим блокування може утримуватися лише одним процесом, тоді як семафор може утримуватися одним або декількома процесами. Спін блокування зачекайте, поки процес звільнить замок, а потім придбає замок. Семафор спить замком, тобто чекає і лягає спати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.