- •Типы блокировок (механизмов синхронизации)
- •Определение семафора
- •Применение семафоров
- •Проблемы семафоров
- •Мьютексы в Win32 api
- •Мьютексы в Unix-подобных системах
- •Мьютексы в языке Си
- •Простейший пример взаимной блокировки
- •Применение спинлоков
- •Проблемы спинлоков и методы их решения
- •Специфика многопроцессорных и однопроцессорных конфигураций
- •Альтернативы спинлоков
- •Прочие модификации спинлоков
Специфика многопроцессорных и однопроцессорных конфигураций
Бытует распространённое мнение о том, что в пользовательских приложениях, работающих под управлением многозадачных ОС, использование спинлоков недопустимо, так как ожидание освобождения спинлока приводит к активному ожиданию в цикле, впустую расходующее вычислительные ресурсы процессора, а для синхронизации пользовательских программ должны применяться высокоуровневые примитивы, которые предполагают пассивное ожидание — если данная нить не может продолжить выполнение, то она отдаёт управление ОС, а не крутится в цикле ожидания спинлока (который потенциально может быть бесконечным). На самом деле данное утверждение является справедливым на 100 % только для однопроцессорных систем. Во многих случаях применение спинлоков в SMP-конфигурациях ведёт к повышению эффективности в случае, если опрос и захват спинлока оказываются быстрее, чем вызов захвата мьютекса в ядре.
Главным критерием здесь является contention — «жёсткость» соревнования за ресурс. Слабонагруженный ресурс, не являющийся популярным местом исполнения, ведёт себя иначе, чем сильно нагруженный, захватываемый и освобождаемый очень часто.
Кроме того, в той же Windows есть разновидности мьютексов (например, общеизвестная CRITICAL_SECTION, или же FAST_MUTEX в ядре), которые сначала работают как spinlock, используя опрос значения в памяти, и только потом, по истечении большого количества опросов, переходят в ядро к блокирующему ожиданию. Такие объекты сочетают лучшие качества спинлоков (минимальная цена захвата) и мьютексов (отсутствие растраты ресурса процессора на опрос).
Применение спинлоков
Случаи, когда применение в пространстве пользователя спинлоков даёт ощутимый эффект:
Внутри участка защищаемого кода находится несколько связанных переменных, время модификации которых может быть в сотни и даже тысячи раз меньше, чем переключение контекста процессором, что является особенно дорогой операцией, особенно на современных системах.
Блокировка не участков кода, а данных (с каждой структурой данных, которая должна атомарно изменяться как единое целое, связан спинлок, её защищающий)
Оптимизация кода, когда необходимо уменьшить нагрузку, возникающую за счёт слишком частого переключения контекста
Случаи, когда применение спинлоков не оправдано и является пустой тратой процессорных ресурсов:
Длительные блокирующие операции внутри защищаемого участка кода (дисковый и сетевой ввод-вывод может выполняться очень долго по процессорным меркам)
Однопроцессорные конфигурации — весь остаток кванта времени процессор проводит в холостом цикле.
Проблемы спинлоков и методы их решения
На современных процессорах цикл ожидания может выполняться очень быстро за счет особенностей конвейерной архитектуры, что помимо наматывания холостых циклов может приводить к более интенсивному нагреву, чем при обычной работе.
В Pentium 4 и последующих моделях процессоров Intel введена специальная ассемблерная команда для вставки внутрь цикла pause (опкод 0xf3 0x90, аналогичный команде rep nop для совместимости со старыми процессорами) предназначение которой проинструктировать процессор, что данный цикл является циклом ожидания, и позволяет процессору с поддержкой нескольких потоков на одном ядре перейти к следующему потоку.
Версии Windows от Windows 7 оптимизированы на работу в качестве «гостя» в виртуальной машине, и в них вместо pause в случаях, когда ОС исполняется как гость, используется специальный вызов «уведомить гипервизор о том, что мы в цикле ожидания».
