Добавлен: 29.10.2018
Просмотров: 48006
Скачиваний: 190
11.4. Процессы и потоки в Windows
1001
Для улучшения масштабируемости алгоритмов планирования для многопроцессорных
систем с большим количеством процессоров планировщик старается не использовать
блокировку, которая защищает доступ к глобальному массиву списков приоритета.
Вместо этого он смотрит, нельзя ли непосредственно диспетчеризировать готовый
к выполнению поток для работы на том процессоре, где ему следует выполняться.
Для каждого потока планировщик поддерживает идею его «идеального» процессора
(ideal processor) и пытается запланировать его выполнение именно на этом процес-
соре (по возможности). Это улучшает производительность системы, поскольку ис-
пользуемые потоком данные, скорее всего, уже имеются в наличии в принадлежащем
его идеальному процессору кэше. Планировщик знает о таких многопроцессорных
системах, в которых каждый процессор имеет собственную память и которые могут
выполнять программы из любой области памяти (однако если это не локальная для
данного процессора память, то стоимость такой операции выше). Такие системы назы-
ваются компьютерами с архитектурой NUMA (NonUniform Memory Access). На таких
компьютерах планировщик старается оптимизировать размещение потока. Диспетчер
памяти пытается выделить физические страницы в том узле NUMA, который принад-
лежит идеальному процессору (когда в потоке происходит страничная ошибка памяти).
Массив заголовков очередей изображен на рис. 11.13. На схеме показано, что реально
имеется четыре категории приоритетов: real-time, user, zero и idle (значение которого
фактически равно –1). Это требует особого пояснения. Приоритеты 16–31 называются
системными и предназначены для создания систем, удовлетворяющих ограничениям
реального времени, таким как предельные сроки, необходимые для мультимедийных
презентаций. Потоки с приоритетами реального времени выполняются до потоков
с динамическими приоритетами (но не раньше DPC и ISR). Если приложение реаль-
ного времени хочет выполняться в системе, то ему могут потребоваться такие драйверы
устройств, которые не имеют длительного выполнения DPC или ISR (поскольку это
может вызвать пропуск потоками реального времени их конечных сроков).
Рис. 11.13. Windows Vista поддерживает 32 приоритета для потоков
1002
Глава 11. Изучение конкретных примеров: Windows 8
Обычные пользователи запускать потоки реального времени не могут. Если бы поль-
зовательский поток выполнялся с более высоким приоритетом, чем, например, поток
клавиатуры или мыши, и зациклился, то поток клавиатуры или мыши не смог бы
выполняться, что привело бы к зависанию системы. Право устанавливать приоритет
реального времени требует наличия специальной привилегии в маркере процесса.
Обычные пользователи не имеют этой привилегии.
Потоки приложений обычно выполняются с приоритетами 1–15. При помощи уста-
новки приоритетов процессов и потоков приложение может определить, какие потоки
получают преимущество. Системные потоки обнуления страниц (ZeroPage) работают
с приоритетом 0 и преобразуют свободные страницы в заполненные нулями страницы.
Для каждого реального процессора имеется отдельный поток обнуления страниц.
Каждый поток имеет базовый приоритет, основанный на классе приоритета процесса
и относительном приоритете потока. Однако приоритет, используемый для поиска того
списка, который содержит готовый поток, определяется текущим приоритетом, кото-
рый обычно равен базовому (но это не всегда так). В определенных обстоятельствах
текущий приоритет потока (не потока реального времени) поднимается ядром выше
базового приоритета (но не выше 15). Поскольку массив, изображенный на рис. 11.13,
основан на текущем приоритете, то его изменение влияет на планирование. Потоки
реального времени никогда не корректируются.
Теперь давайте посмотрим, когда приоритет потока повышается. Во-первых, когда опе-
рация ввода-вывода завершается и освобождает находящийся в состоянии ожидания
поток, то его приоритет повышается (чтобы он мог опять быстро запуститься и начать
новую операцию ввода-вывода). Идея состоит в том, чтобы поддерживать загрузку
устройств ввода-вывода. Величина повышения приоритета зависит от устройства
ввода-вывода — обычно для диска это 1, для последовательной линии — 2, для клави-
атуры — 6, а для звуковой карты — 8.
Во-вторых, если поток ждал на семафоре, мьютексе или другом событии, то при его
освобождении он получает повышение приоритета на два уровня, если находится в фо-
новом процессе (например, процесс, который управляет окном, в которое посылается
ввод с клавиатуры), и на один уровень во всех остальных случаях. Такое повышение
поднимает интерактивные процессы над большим количеством процессов, находящих-
ся на уровне 8. И наконец, если поток графического интерфейса пользователя просы-
пается по причине наличия ввода от пользователя, то он также получает повышение
(по той же самой причине).
Такие повышения выполняются не навсегда. Они вступают в действие немедленно
и могут вызвать изменения в планировании процессора. Однако если поток использует
весь свой следующий квант, то он теряет один уровень приоритета и перемещается
вниз на одну очередь в массиве приоритетов. Если же он использует второй полный
квант, то он перемещается вниз еще на один уровень, и так до тех пор, пока не дойдет
до своего базового уровня (где и останется до следующего повышения).
Есть еще один случай корректировки приоритетов. Представьте себе, что два потока
работают вместе над задачей «производитель — потребитель». Работа производителя
труднее, так что он получает более высокий приоритет (например, 12), чем потребитель
(приоритет 4). В определенный момент производитель заполняет совместно использу-
емый буфер и блокируется на семафоре (как показано на рис. 11.14, а).
До того как потребитель получает возможность запуститься, какой-то другой поток
с приоритетом 8 получает готовность и начинает выполнение (рис. 11.14, б). Этот поток
11.5. Управление памятью
1003
Рис. 11.14. Пример инверсии приоритетов
сможет выполняться столько, сколько захочет, поскольку имеет более высокий приори-
тет планирования, чем потребитель (а производитель, приоритет которого еще выше,
блокирован). В таких обстоятельствах производитель никогда не сможет запуститься
(пока поток с приоритетом 8 не уйдет). Эта проблема хорошо известна как инверсия
приоритетов
(priority inversion).
Windows решает проблему инверсии приоритетов между потоками ядра, приме-
няя в планировщике потоков средство под названием Autoboost (автоповышение).
Autoboost автоматически отслеживает зависимости от ресурсов между потоками и по-
вышает планируемый приоритет потоков, удерживающих ресурсы, необходимые для
потоков с более высоким уровнем приоритета.
Windows запускается на персональных компьютерах, у которых в любой момент вре-
мени обычно имеется только одна интерактивная сессия. Но Windows поддерживает
также режим сервера терминала — terminal server, в котором с помощью using RDP
(Remote Desktop Protocol — протокола удаленного рабочего стола) по сети поддержи-
вается несколько интерактивных сессий. При запуске нескольких пользовательских
сессий один пользователь легко может помешать другому, потребляя слишком много
ресурсов процессора. В Windows реализован справедливый алгоритм DFSS (Dynamic
Fair-Share Scheduling — динамическое справедливое планирование), который не дает
сессиям работать черезмерно. В DFSS для приведения в порядок потоков каждой
сессии используется планирование групп (scheduling groups). Внутри каждой группы
потоки планируются в соответствии с обычной политикой планирования, имеющей-
ся в Windows, но каждой группе дается больше или меньше доступа к процессору на
основе того, как долго эта группа выполнялась в совокупности. Относительные при-
оритеты групп корректируются медленно, чтобы позволить игнорировать краткие
всплески активности и уменьшить объем разрешенного группе времени, если она долго
использовала слишком много процессорного времени.
11.5. Управление памятью
Windows имеет весьма изощренную и сложную систему виртуальной памяти. Для ее
использования имеются функции Win32, реализованные диспетчером памяти — самым
1004
Глава 11. Изучение конкретных примеров: Windows 8
крупным компонентом исполнительного уровня NTOS. В последующих разделах мы рас-
смотрим фундаментальные концепции, вызовы интерфейса Win32, а также реализацию.
11.5.1. Фундаментальные концепции
В Windows каждый пользовательский процесс имеет собственное виртуальное адресное
пространство. Для компьютеров х86 виртуальные адреса имеют длину 32 бита, так что
каждый процесс имеет 4 Гбайт виртуального адресного пространства, по 2 Гбайта поль-
зователю и ядру. На машинах x64 и пользователь и ядро получают больше виртуальных
адресов, чем они смогут разумно использовать в обозримом будущем. И в компьютерах
х86, и в компьютерах х64 виртуальное адресное пространство имеет замещение страниц
по требованию со страницей фиксированного размера — 4 Кбайт, но в некоторых случа-
ях, как мы скоро увидим, применяются также большие страницы размером по 2 Мбайт
(за счет использования каталога страниц и обхода соответствующей таблицы страниц).
Виртуальное адресное пространство для трех пользовательских процессов на ком-
пьютере х86 показано в упрощенной форме на рис. 11.15. Нижние и верхние 64 Кбайт
виртуального адресного пространства каждого процесса обычно никуда не отобража-
ются. Так было сделано специально, чтобы помочь отлавливать программные ошибки
и смягчить уязвимости определенногог типа.
Закрытые
Закрытые
Закрытые
Рис. 11.15. Виртуальное адресное пространство для трех пользовательских процессов
на компьютере х86. Белым цветом показаны закрытые области каждого процесса.
Заштрихованные области являются общими для всех процессов
С отметки 64 Кбайт начинаются пользовательские закрытые код и данные. Эта область
простирается почти до 2 Гбайт. Верхние 2 Гбайт содержат операционную систему
(включая код, данные, а также резидентный и нерезидентный пулы). Верхние 2 Гбайт —
это виртуальная память ядра, которая совместно используется всеми пользователь-
скими процессами (кроме данных виртуальной памяти, таких как таблицы страниц
11.5. Управление памятью
1005
и списки рабочих наборов, которые у каждого процесса свои). Виртуальная память ядра
доступна только из режима ядра. Причина совместного использования виртуальной
памяти процессов ядром состоит в том, что когда поток делает системный вызов, то
он захватывается в режим ядра и может продолжать выполнение без изменения карты
памяти. Все, что нужно сделать, — это переключиться на стек ядра потока. С точки
зрения производительности это большая победа, и все это похоже на UNIX. Поскольку
страницы пользовательского режима процесса по-прежнему доступны, то код режима
ядра может читать параметры и выполнять доступ к буферам без необходимости пере-
ключаться между адресными пространствами или временного дублирования страниц
в оба пространства. Здесь получается компромисс между уменьшением приходящегося
на один процесс закрытого адресного пространства и увеличением скорости выполне-
ния системных вызовов.
Windows позволяет потокам прикрепляться к другим адресным пространствам (во
время выполнения в ядре). Прикрепление к адресному пространству позволяет по-
току обращаться ко всему пространству адресов пользовательского режима, а также
к специфичным для процесса частям адресного пространства ядра (таким, как карта
таблиц страниц). Перед возвращением в пользовательский режим потоки должны
переключаться обратно в исходное адресное пространство.
Выделение виртуальных адресов
Страница виртуальных адресов может быть в одном из трех состояний: недействитель-
ная, зарезервированная или зафиксированная. Недействительная страница (invalid
page) не отображается на объект раздела памяти, и ссылка на нее вызывает странич-
ную ошибку, которая приводит к нарушению доступа. После того как код или данные
отображаются на виртуальную страницу, страница называется зафиксированной
(commited). Страничная ошибка на зафиксированной странице приводит к отображе-
нию страницы с вызвавшим ошибку виртуальным адресом на одну из страниц, пред-
ставленных объектом сегмента или сохраненных в файле подкачки. Часто для этого
необходимо бывает выделить физическую страницу, а также выполнить ввод-вывод для
файла, представленного объектом сегмента (чтобы прочитать данные с диска). Однако
страничные ошибки могут возникать и потому, что нужно обновить элемент таблицы
страниц, поскольку та физическая страница памяти, на которую он ссылается, все еще
кэширована в памяти (в этом случае ввод-вывод не нужен). Это называется мягкой
ошибкой
(soft faults), и скоро мы обсудим это подробнее.
Виртуальная страница может быть также в зарезервированном (reserved) состоянии.
Зарезервированная виртуальная страница недействительна, но эти виртуальные адреса
никогда не будут выделяться диспетчером памяти для других целей. Например, когда
создается новый поток, то многие страницы пространства стека пользовательского
режима резервируются в пространстве виртуальных адресов процесса, но только одна
страница фиксируется. По мере роста стека диспетчер виртуальной памяти будет
автоматически фиксировать дополнительные страницы (до тех пор, пока зарезервиро-
ванный объем практически истощится). Зарезервированные страницы действуют как
страницы защиты — они предохраняют от слишком большого роста стека и перезаписи
данных других процессов. Резервирование всех виртуальных страниц означает, что
стек может в итоге разрастись до максимального размера (не рискуя, что некоторые
необходимые для стека последовательные страницы виртуального адресного про-
странства могут быть отданы для других целей). Кроме атрибутов «недействительная»,