- •Глава 4.
- •Многопоточность
- •Функциональность потоков
- •Потоки на пользовательском уровне и на уровне ядра
- •Другие схемы
- •4.2 Симметричная многопроцессорная обработка
- •Организация симметричной многопроцессорной системы
- •Архитектура многопроцессорных операционных систем
- •4.3. Микроядра
- •Архитектура микроядра
- •Достоинства архитектуры с микроядром
- •Производительность микроядра
- •Архитектура микроядер
- •4.4. Потоки и smp в windows 2000
- •Объекты процессов и потоков
- •Многопоточность
- •Состояния потоков
- •Поддержка подсистем операционной системы
- •Поддержка симметричной многопроцессорной обработки
- •4.5. Управление потоками и smp в solaris
- •Мотивация
- •Структура процессов
- •Выполнение потоков
- •Прерывания в роли потоков
- •4 6. Управление процессамии потоками в linux
- •4.7. Резюме, ключевые термины и контрольные вопросы
- •Контрольные вопросы
- •4.8. Рекомендуемая литература
- •4.9. Задачи
Производительность микроядра
Одним из часто упоминаемых потенциальных недостатков микроядер является их низкая производительность. Создание сообщения и отправка его через микроядро с последующим получением и декодированием ответа занимает больше времени, чем непосредственный вызов сервиса. Однако при этом в действие вступают и другие факторы, поэтому трудно делать выводы о масштабах потери производительности и о том, есть ли она вообще.
Многое зависит от размеров и функциональных возможностей микроядра. В [LIED96a] подытожены результаты некоторых исследований, свидетельствующие о значительной потере производительности в так называемых микроядрах первого поколения. От этих потерь не удается избавиться, несмотря на усилия, направленные на оптимизацию кода микроядра. В попытке решить проблему разработчики увеличивали микроядро, снова включая в операционную систему критические серверы и драйверы. Основными примерами такого подхода являются операционные системы Mach и Chorus. Избирательное увеличение функциональности микроядра приводит к снижению количества переключений между пользовательским режимом и режимом ядра, а также переключений адресных пространств процессов. Хотя такой подход и снижает потери производительности, это происходит за счет сильных сторон архитектуры операционной системы с микроядром: минимальных интерфейсов, гибкости и т.п.
Другой подход состоит в том, чтобы сделать микроядро не больше, а еще меньше. В [LIED96b] приводятся данные о том, что в микроядре, обладающем надлежащей архитектурой, удается избежать потерь производительности и наряду с этим повысить его гибкость и надежность. Чтобы вы имели представление о размерах микроядер, заметим, что типичное микроядро первого поколения состоит из 300 Кбайт кода и содержит в себе до 140 интерфейсов системных вызовов. Примером маленького микроядра второго поколения является ядро операционной системы L4 [HART97, LIED95], которое состоит из 12 Кбайт кода и содержит в себе 7 интерфейсов системных вызовов. Опыт работы с такими системами показывает, что они являются не менее, а иногда даже более, эффективными, чем такие мощные системы, как UNIX.
Архитектура микроядер
Из-за того что различные микроядра обладают разными возможностями и размером, невозможно четко сформулировать правила, определяющие круг функций, предоставляемых микроядром, и его структуру. Чтобы дать представление об архитектуре микроядра, в этом разделе представлен минимальный набор его функций и сервисов.
В микроядро должны входить те функции, которые непосредственно зависят от аппаратного обеспечения, а также те, которые нужны для поддержки серверов и приложений, работающих в пользовательском режиме. Эти функции относятся к общим категориям функций низкоуровневого управления памятью, межпроцессного взаимодействия, а также управления вводом-выводом и прерываниями.
Низкоуровневое управление памятью
Чтобы в микроядре можно было реализовать защиту на уровне процессов, в нем должен обеспечиваться контроль над аппаратной концепцией адресного пространства. Если микроядро будет отвечать за отображение каждой виртуальной страницы в физический страничный блок, то блок управления памятью, включая систему защиты адресного пространства одного процесса от другого, а также алгоритм замены страниц и другие логические схемы страничной организации памяти, можно реализовать вне ядра. Например, вынесенный за пределы ядра модуль виртуальной памяти принимает решение, когда загружать страницу в память и какую из тех страниц, которые уже содержатся в памяти, следует заменить. Микроядро отображает ссылки на эти страницы в физические адреса основной памяти.
Впервые идея о том, что системы страничной организации памяти и управления виртуальной памятью можно вынести за пределы ядра, появилась вместе с- внешней системой страничной организации операционной системы Mach [YOUN87]. Принцип работы этой системы поясняется на рис. 4.11. Когда поток приложения обращается к странице, которая отсутствует в основной памяти, возникает прерывание из-за отсутствия страницы, и управление перехватывается ядром. После этого ядро отправляет системе страничной организации сообщение, в котором указывается запрашиваемая страница. Система страничной организации может принять решение загрузить данную страницу и выделить для этого страничный блок. Система страничной организации и ядро должны взаимодействовать между собой, чтобы логические операции, которые происходят в этой системе, отображались в физическую память. Как только нужная страница станет доступна, система страничной организации отправляет приложению сообщение о том, что оно может продолжить работу.
Такая технология позволяет внешнему по отношению к ядру процессу отображать файлы и базы данных в пользовательские адресные пространства без участия ядра. Вне ядра можно реализовать специализированные стратегии разделения памяти.
В [LIED95] предлагается оставить в микроядре набор, состоящий всего из трех операций, которые способны поддерживать внешние системы страничной организации памяти и управления внешней памятью. В этот набор входят следующие операции.
Предоставление (grant). Владелец адресного пространства (процесс) может предоставлять некоторые свои страницы другому процессу. Ядро удаляет эти страницы из адресного пространства первого процесса и передает их второму процессу.
Отображение (mар). Процесс может отображать любые свои страницы в адресное пространство другого процесса, после чего оба процесса будут иметь доступ к этим страницам. При этом создается общая область памяти, совместно используемая двумя процессами. Ядро не меняет информацию о принадлежности первоначальному процессу-владельцу, но при этом выполняет отображение, предоставляющее другому процессу доступ к этим страницам.
Восстановление (flush). Процесс может восстановить любые страницы, предоставленные другим процессам или отображенные в их адресное пространство.
Вначале ядро определяет всю физическую память как единое адресное пространство, которым управляет основной системный процесс. При создании новых процессов страницы первоначального общего адресного пространства могут передаваться или отображаться в эти новые процессы. Такая схема позволяет одновременно поддерживать несколько схем организации виртуальной памяти.
Взаимодействие между процессами
Основной формой взаимодействия между процессами или потоками в операционной системе с микроядром являются сообщения. Сообщение включает в себя заголовок, в котором указаны идентификаторы процесса-отправителя и процесса-адресата, а также тело с пересылаемыми данными, указателем на блок данных или некоторыми управляющими сведениями о процессе. Обычно можно считать, что взаимодействие между процессами основано на относящихся к этим процессам портах. Порт — это, по сути, очередь сообщений, предназначенных для определенного процесса. С портом связан список возможностей, в котором указано, с какими процессами данный процесс может обмениваться информацией. Процесс может разрешать доступ к себе, отправляя ядру сообщение, в котором указывается новая возможность порта.
Здесь уместно сделать одно замечание по поводу передачи сообщений. Если адресные пространства двух процессов не перекрываются, то передача сообщения от одного процесса другому включает в себя копирование одной области памяти в другую. Таким образом, скорость такой передачи сообщения ограничена скоростью работы памяти, которая несравнимо меньше, чем скорость процессора. Поэтому в современных исследованиях наблюдается интерес к межпроцессному взаимодействию, основанному на потоках, и к таким схемам разделения памяти, как многократное отображение страниц (в которых одна и та же страница используется многими процессами).
Управление вводом-выводом и прерываниями
В архитектуре микроядра имеется возможность обрабатывать аппаратные прерывания подобно сообщениям, а также включить в адресное пространство порты ввода-вывода. Такое микроядро может распознавать прерывания, но не обрабатывает их. Вместо этого оно генерирует сообщение процессу, функционирующему на пользовательском уровне и связанному с данным прерыванием. Таким образом, когда прерывание разрешено, с ним сопоставляется процесс на пользовательском уровне, и такое отображение поддерживается ядром. Преобразование прерываний в сообщения должно выполняться микроядром, однако ядро не принимает участия в обработке аппаратно-зависимых прерываний.
В [LIED96a] предлагается рассматривать аппаратное обеспечение как набор потоков, которые обладают уникальными идентификаторами и отправляют сообщения (содержащие только идентификатор данного потока) соответствующим программным потокам в пользовательском пространстве. Поток-получатель выясняет, является ли данное сообщение прерыванием, а также определяет вид этого прерывания. Общая структура такого кода, выполняющегося на пользовательском уровне, имеет следующий вид:
driver thread;
do
waitFor (msg, sender);
if (sender== обрабатываемое_прерывание)
{
чтение/запись в порты ввода-вывода;
сброс аппаратного прерывания
}
else…
while (true);