Барьер | Описание |
---|---|
rmb() | Предотвращает изменение порядка выполнения операций чтения данных из памяти при переходе через барьер |
read_barrier_depends() | Предотвращает изменение порядка выполнения операций чтения данных из памяти при переходе через барьер, но только для операций чтения, которые зависимы друг от друга |
wmb() | Предотвращает изменение порядка выполнения операций записи данных в память при переходе через барьер |
mb() | Предотвращает изменение порядка выполнения операций чтения и записи данных при переходе через барьер |
smp_rmb() | Для SMP-ядер эквивалентно функции rmb() , а для ядер, рассчитанных на однопроцессорные машины, эквивалентно функции barrier() |
smp_read_barrier_depends() | Для SMP-ядер эквивалентно функции read_barrier_depends() , а для ядер, рассчитанных на однопроцессорные машины, эквивалентно функции barrier() |
smp_wmb() | Для SMP-ядер эквивалентно функции wmb() , а для ядер, рассчитанных на однопроцессорные машины, эквивалентно функции barrier() |
smp_mb() | Для SMP-ядер эквивалентно функции mb() , а для ядер, рассчитанных на однопроцессорные машины, эквивалентно функции barrier() |
barrier() | Предотвращает оптимизации компилятора по чтению и записи данных при переходе через барьер |
Следует заметить, что эффекты установки барьеров могут быть разными для разных аппаратных платформ. Например, если машина не изменяет порядок операций записи (как в случае набора микросхем Intel x86), то функция wmb()
не выполняет никаких действий. Можно использовать соответствующий барьер памяти для самой плохой ситуации (т.е. для процессора с самым плохим порядком выполнения), и ваш код будет скомпилирован оптимально для вашей аппаратной платформы.
Резюмирование по синхронизации
В этой главе было рассказано о том, как применять на практике понятия, описанные в предыдущей главе, чтобы лучше разобраться с функциями ядра, которые помогают осуществить синхронизацию и параллелизм. Вначале были рассмотрены самые простые методы, которые позволяют гарантировать сихронизацию, — атомарные операции. Далее были описаны спин-блокировки — наиболее часто используемые типы блокировок в ядре, которые построены на основе периодической проверки в цикле условия освобождения блокировки и позволяют гарантировать, что доступ к ресурсу получит только один поток выполнения. После этого были рассмотрены семафоры — блокировки, которые переводят вызывающий процесс в состояние ожидания, а также более специализированные типы элементов синхронизации — условные переменные и секвентные блокировки. Мы получили удовольствие от блокировки BKL, рассмотрели методы запрещения вытеснения кода ядра и коснулись барьеров. Диапазон большой.
Вооружённые арсеналом методов синхронизации из данной главы теперь вы сможете писать код ядра, который защищён от состояний конкуренции за ресурсы и позволяет обеспечить необходимую синжронизацию с помощью самого подходящего для этого инструментария.
Глава 10
Таймеры и управление временем
Отслеживание хода времени очень важно для ядра. Большое количество функций, которые выполняет ядро, управляются временем (time driven), в отличие от тех функций, которые выполняются по событиям[53] (event driven). Некоторые из этих функций выполняются периодически, как, например, балансировка очередей выполнения планировщика или обновление содержимого экрана. Такие функции вызываются в соответствии с постоянным планом, например 100 раз в секунду. Другие функции, такие как отложенные дисковые операции ввода-вывода, ядро планирует на выполнение в некоторый относительный момент времени в будущем. Например, ядро может запланировать работу на выполнение в момент времени, который наступит позже текущего на 500 миллисекунд. Наконец, ядро должно вычислять время работы системы (uptime), а также текущую дату и время.