- •Типы блокировок (механизмов синхронизации)
- •Определение семафора
- •Применение семафоров
- •Проблемы семафоров
- •Мьютексы в Win32 api
- •Мьютексы в Unix-подобных системах
- •Мьютексы в языке Си
- •Простейший пример взаимной блокировки
- •Специфика многопроцессорных и однопроцессорных конфигураций
- •Применение спинлоков
- •Проблемы спинлоков и методы их решения
- •Альтернативы спинлоков
- •Прочие модификации спинлоков
Синхронизация (от др.-греч. σύγχρονος — одновременный) в информатике обозначает одно из двух: синхронизацию процессов, либо синхронизацию данных.
Синхронизация процессов — приведение двух или нескольких процессов к такому их протеканию, когда определённые стадии разных процессов совершаются в определённом порядке, либо одновременно.
Синхронизация необходима в любых случаях, когда параллельно протекающим процессам необходимо взаимодействовать. Для её организации используются средства межпроцессного взаимодействия (см. "Управление процессами"). Среди наиболее часто используемых средств — сигналы и сообщения, семафоры и мьютексы, каналы (pipe), совместно используемая память.
Синхронизация данных — ликвидация различий между двумя копиями данных. Предполагается, что ранее эти копии были одинаковы, а затем одна из них, либо обе были независимо изменены.
Способ синхронизации данных зависит от делаемых дополнительных предположений. Главной проблемой тут является то, что независимо сделанные изменения могут быть несовместимы друг с другом (так называемый «конфликт правок»), и даже теоретически не существует общего способа разрешения подобных ситуаций.
Тем не менее, есть ряд частных способов, применимых в тех или иных случаях:
Наиболее простой способ: предполагают, что изменения вносились лишь в одну из копий — «рабочую» — и другая копия просто перезаписывается её содержимым. Этот способ реализуют большинство приложений синхронизации; в силу необратимости делаемых изменений пользователю даётся выбор, какую копию считать «главной».
Если данные представляют собой набор независимых записей (то есть любое сочетание записей является корректным — это, напр., телефонная книга), то можно просто объединить множества записей. Это ликвидирует риск потери информации, но чтобы удалить запись из набора, этот способ приходится сочетать с первым.
Если наборы синхронизируются неоднократно, можно автоматически вводить в них дополнительную служебную информацию: дата и время последнего изменения записи, пометки об удалённых записях (стираются после следующей синхронизации или через достаточно большое время) и пр. . Этот подход используется, например, в Outlook.
Обрабатывать конфликты правок: автоматически (если возможно), иначе — вручную. Этот, наиболее общий способ применяется только если указанные выше упрощённые недопустимы — например, в системах контроля версий. Так, CVS при обнаружении двух независимых изменений объявляет о «конфликте» и либо (в простых случаях) разрешает его автоматически, либо предоставляет пользователю разрешить его вручную. В этих случаях конфликтов стараются просто избегать — например, распределением областей компетенции.
Одним из механизмов синхронизации данных является репликация, которая в частности находит применение для синхронизации содержимого баз данных.
Перечень групп Win API-функций синхронизации:
1. Asynchronous functions (асинхронные функции)
2. Condition variable and SRW lock functions (условная переменная и SRW-лок функции)
3. Critical section functions (критическая секция)
4. Event functions (события)
5. One-time initialization functions (одноразовые функции инициализации)
6. Interlocked Functions (сцепление)
7. Mutex functions (мютекс)
8. Private namespace functions (частное пространство имен)
9. Semaphore functions (симафор)
10. Singly-linked list functions (связный список)
11. Synchronization barrier functions (барьер синхронизации)
12. Timer-queue timer functions (таймер очереди)
13. Wait functions (функция ожидания)
14. Waitable-timer functions (сторожевой таймер)
Блокировка — механизм синхронизации, позволяющий обеспечить исключительный доступ к разделяемому ресурсу между несколькими потоками. Блокировки — это один из способов обеспечить политику управления распараллеливанием.
Типы блокировок (механизмов синхронизации)
В основном, используется мягкая блокировка, при этом предполагается что каждый поток пытается получить блокировку перед доступом к соответствующему разделяемому ресурсу. В некоторых системах предоставляется механизм обязательной блокировки, при его использовании попытка несанкционированного доступа к заблокированному ресурсу будет прервана, через создание исключения в потоке, который пытался получить доступ.
Семафор — самый простой тип блокировки. С точки зрения доступа к данным не делается никаких различий между режимами доступа: общим (только чтение) или эксклюзивным (чтение и запись). В режиме общего доступа несколько потоков могут запросить блокировку для доступа к данным в режиме «только чтение». Также используется эксклюзивный режим доступа в алгоритмах обновления и удаления.
Типы блокировок различают по стратегии блокировки продолжения исполнения потока. В большинстве реализаций запрос блокировки препятствует дальнейшему исполнению потока, пока не появится доступ к заблокированному ресурсу.
Спинлок — это блокировка, которая ожидает в цикле, пока не появится доступ. Такая блокировка очень эффективна, если поток ожидает блокировку незначительный интервал времени, это позволяет избежать избыточной перепланировки потоков. Затраты на ожидание доступа будут значительными при длительном удержании блокировки одним из потоков.
Для эффективной реализации механизма блокировки требуется поддержка на аппаратном уровне. Аппаратная поддержка может быть реализована в виде одной или нескольких атомарных операциях, таких как «test-and-set», «fetch-and-add» или «compare-and-swap». Такие инструкции позволяют без прерываний проверить, что блокировка свободна и, если это так, то занять блокировку.
В однопроцессорных системах есть возможность исполнять инструкции без аппаратных прерываний, используя специальные инструкции или префиксы инструкции, которые временно отключают прерывания, но такой подход не работает в многопроцессорных системах с общей памятью. Полная поддержка блокировок в многопроцессорном окружении может потребовать достаточно сложной аппаратной и программной поддержки со значительными проблемами синхронизации.
Сигна́л — код (символ, знак), созданный и переданный в пространство (по каналу связи) одной системой, либо возникший в процессе взаимодействия нескольких систем. Смысл и значение сигнала проявляются в процессе его регистрации второй (принимающей) системой.
Семафо́р — объект, ограничивающий количество потоков, которые могут войти в заданный участок кода. Определение введено Эдсгером Дейкстрой. Семафоры используются при передаче данных через разделяемую память.
Определение семафора
Семафор — это объект, с которым можно выполнить три операции.
init(n):
счётчик := n
enter():
ждать пока счётчик станет больше 0; после этого уменьшить счётчик на единицу.
leave():
увеличить счётчик на единицу.
Предположим, что есть такой участок кода:
semaphore.init(5);
// .....
// .....
void DoSomething()
{
semaphore.enter();
// .......
semaphore.leave();
}
Тогда не более пяти потоков могут одновременно выполнять функцию DoSomething().
В более сложных семафорах может использоваться очередь; при этом потоки, ожидающие освобождения семафора, будут проходить через семафор именно в том порядке, в котором они вызывали enter().
