Так как ядро операционной системы Linux может быть сконфигурировано на этапе компиляции, имеет смысл "подогнать" ядро под данный тип машины. Важной функцией ядра является поддержка симметричной многопроцессорной обработки (SMP), которая включается с помощью параметра конфигурации ядра CONFIG_SMP
. На однопроцессорной (uniprocessor, UP) машине исчезают многие проблемы, связанные с блокировками, и, следовательно, если параметр CONFIG_SMP
не установлен, то код, в котором нет необходимости, не компилируется в исполняемый образ ядра. Например, это позволяет на однопроцессорной машине отказаться от накладных расходов, связанных со спин-блокировками. Аналогичный прием используется для параметра CONFIG_PREEMPT
(параметр ядра, который указывает, будет ли ядро вытесняемым). Такое решение является отличным проектным решение, поскольку позволяет использовать общий четкий исходный код, а различные механизмы блокировок используются при необходимости. Различные комбинации параметров CONFIG_SMP
и CONFIG_PREEMPT
на различных аппаратных платформах позволяют компилировать в ядро различные механизмы блокировок.
При написании кода необходимо обеспечить все возможные варианты защиты для всех возможных случаев жизни и всех возможных сценариев, которые будут рассмотрены.
При написании кода ядра следует задать себе следующие вопросы.
• Являются ли данные глобальными? Может ли другой поток выполнения, кроме текущего, обращаться к этим данным?
• Являются ли данные совместно используемыми из контекста процесса и из контекста прерывания? Используют ли их совместно два обработчика прерываний?
• Если процесс во время доступа к данным будет вытеснен, может ли новый процесс, который запланирован на выполнение, обращаться к этим же данным?
• Может ли текущий процесс перейти в состояние ожидания (заблокироваться) на какой-либо операции? Если да, то в каком состоянии он оставляет все совместно используемые данные?
• Что запрещает освободить память, в которой находятся данные?
• Что произойдет, если эта же функция будет вызвана на другом процессоре?
• Как все это учесть?
Если коротко, то почти все глобальные данные требуют применения тех или других методов синхронизации, которые будут рассмотрены в следующей главе.
Взаимоблокировки
Взаимоблокировка (тупиковая ситуация, deadlock) — это состояние, при котором каждый поток ожидает на освобождение одного из ресурсов, а все ресурсы при этом захвачены. Потоки будут ожидать друг друга, и они никогда не смогут освободить захваченные ресурсы. Поэтому ни один из потоков не сможет продолжать выполнение, что означает наличие взаимоблокировки.
Хорошая аналогия — это перекресток, на котором стоят четыре машины, которые подъехали с четырех разных сторон. Каждая машина ожидает, пока не уедут остальные машины, и ни одна из машин не сможет уехать; в результате получается тупиковая ситуация.
Самый простой пример взаимоблокировки— это
захватить блокировку
захватить блокировку еще раз
ждать, пока блокировка не будет освобождена
...