Шрифт:
Диспетчеризация и реальный мир
До настоящего момента мы обсуждали дисциплины диспетчеризации и состояния потоков, но практически ничего не сказали относительно того, почему и когда происходит собственно перепланирование. Существует распространенное заблуждение, что перепланирование «просто случается», безо всяких реальных причин. И в общем-то, для проектирования это довольно полезная абстракция! Однако, очень важно понимать, почему происходит перепланирование. Вспомним рисунок «Схема алгоритма диспетчеризации» (в разделе «Роль ядра»).
Перепланирование может иметь только три причины:
• аппаратное прерывание;
• системный вызов;
• сбой (исключение).
Перепланирование по аппаратному прерыванию
Перепланирование из-за аппаратного прерывания можно разделить на две категории:
• по прерыванию от таймеров;
• по прерыванию от других аппаратных средств.
Часы реального времени генерируют периодические прерывания для ядра, организуя перепланирование во времени.
Например, если вы производите вызов
Другие потоки могут ожидать аппаратные прерывания от внешних устройств, таких как последовательный порт, жесткий диск или аудио платы. В этом случае они блокируются в ядре, ожидающем аппаратное прерывание. Поток будет переупорядочен ядром только после того, как ядро сгенерирует «событие».
Перепланирование по системным вызовам
Если поток делает системный вызов, перепланирование выполняется немедленно и может рассматриваться как асинхронное в отношении прерываний таймера и других прерываний.
Например, выше мы приводили пример вызова функции
Системных вызов, вызывающи процесс обязательного перепланирования, очень много. Большинство их них достаточно очевидны. Перечислим некоторые из них:
• функции таймера (например, sleep);
• функции обмена сообщениями (например, MsgSendv);
• примитивы работы с потоками (например, pthread_cancel или pthread_join).
Перепланирование по исключительным ситуациям
Последняя из вышеперечисленных причин перепланирования — это сбой процессора (CPU fault), который является исключительной ситуацией (exception) — чем-то средним между аппаратным прерыванием и системным вызовом. Исключительные ситуации асинхронны в отношении ядра (подобно прерыванию), но синхронны с вызывающими их пользовательскими программами (подобно вызову ядра — например, такая исключительная ситуация как деление на ноль). Все рассуждения, относящиеся к перепланированию по прерываниям от аппаратных средств и по системным вызовам, относятся и к исключительным ситуациям тоже.
Резюме
Операционная система QNX/Neutrino предлагает богатые возможности диспетчеризации потоков — минимальных диспетчеризуемых единиц. Процесс в QNX/Neutrino определяется как минимальная единица, способная обладать ресурсами (например, областями памяти), и может содержать один или более потоков.
С потоками можно применять любые из следующих методов синхронизации:
• мутексы (mutexes) — владеть мутексом в заданный момент времени может только один поток;
• семафоры (semaphores) — владеть семафором позволяется некоторому фиксированному числу потоков;
• ждущие блокировки (sleepons) — позволяют нескольким потокам блокироваться на нескольких объектах, динамически назначая блокированным потокам соответствующие условные переменные;
• условные переменные (condvars) — подобны ждущим блокировкам, за исключением того, что за распределение условных переменных отвечает программист;
• присоединение (joining) — обеспечивает синхронизацию потока по отношению к завершению другого потока;