Шрифт:
Такое изменение порядка выполнения операций может возникнуть из-за того, что современные процессоры обрабатывают и передают на выполнение инструкции в измененном порядке для того, чтобы оптимизировать использование конвейеров. Это может привести к тому, что инструкции чтения переменных
Рассмотрим простой пример случая, когда можно использовать функцию
Поток 1 Поток 2
Снова без использования барьеров памяти появляется возможность того, что переменной
Макросы
Функция
В табл. 9.10 приведен полный список функций установки барьеров памяти и компилятора, которые доступны для разных аппаратных платформ, поддерживаемых ядром Linux.
Таблица 9.10. Средства установки барьеров компилятора и памяти
Барьер | Описание |
---|---|
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), то функция
Резюмирование по синхронизации
В этой главе было рассказано о том, как применять на практике понятия, описанные в предыдущей главе, чтобы лучше разобраться с функциями ядра, которые помогают осуществить синхронизацию и параллелизм. Вначале были рассмотрены самые простые методы, которые позволяют гарантировать сихронизацию, — атомарные операции. Далее были описаны спин-блокировки — наиболее часто используемые типы блокировок в ядре, которые построены на основе периодической проверки в цикле условия освобождения блокировки и позволяют гарантировать, что доступ к ресурсу получит только один поток выполнения. После этого были рассмотрены семафоры — блокировки, которые переводят вызывающий процесс в состояние ожидания, а также более специализированные типы элементов синхронизации — условные переменные и секвентные блокировки. Мы получили удовольствие от блокировки BKL, рассмотрели методы запрещения вытеснения кода ядра и коснулись барьеров. Диапазон большой.
Вооружённые арсеналом методов синхронизации из данной главы теперь вы сможете писать код ядра, который защищён от состояний конкуренции за ресурсы и позволяет обеспечить необходимую синжронизацию с помощью самого подходящего для этого инструментария.
Глава 10
Таймеры и управление временем
Отслеживание хода времени очень важно для ядра. Большое количество функций, которые выполняет ядро, управляются временем (time driven), в отличие от тех функций, которые выполняются по событиям [53] (event driven). Некоторые из этих функций выполняются периодически, как, например, балансировка очередей выполнения планировщика или обновление содержимого экрана. Такие функции вызываются в соответствии с постоянным планом, например 100 раз в секунду. Другие функции, такие как отложенные дисковые операции ввода-вывода, ядро планирует на выполнение в некоторый относительный момент времени в будущем. Например, ядро может запланировать работу на выполнение в момент времени, который наступит позже текущего на 500 миллисекунд. Наконец, ядро должно вычислять время работы системы (uptime), а также текущую дату и время.
53
Если быть точными, то функции, которые управляются временем, также управляются и событиями. В этом случае событие соответствует ходу времени. В этой главе будут рассмотрены, в основном, события, управляемые временем,так как они встречаются очень часто и являются важными для ядра.
Следует обратить внимание на разницу между относительным и абсолютным временем. Планирование выполнения некоторой работы через 5 секунд в будущем не требует учета абсолютного времени, а только относительного (например, через пять секунд от текущего момента времени). В рассмотренной ситуации расчет текущей даты и времени требует от ядра не только учета хода времени, но и абсолютного измерения времени. Обе концепции являются важными для управления временем.