Ю. Вахалия - UNIX изнутри (2003) (1114670), страница 23
Текст из файла (страница 23)
Однако существуют и очевидные недостатки применения нитей, Однонитевому процессу не нужно заботиться о защите своих данных от других процессов. Многонитевые процессы должны следить за каждым объектом в собственном адресном пространстве. Если к объекту имеет доступ более 3.1. Введение 101 чем одна нить, то с целью предотвращения повреждения данных необходимо применять методы синхронизации.
Адресное пространство Нить Время Рис. 3.2. Многонитевые процессы на однопроцессорной машине На рис. 3.3 показаны два многонитевых процесса, выполняющиеся в многопроцессорной системе. Все нити каждого процесса совместно используют одно и то же адресное пространство, однако каждая из них выполняется на отдельном процессоре. Таким образом, все эти нити функционируют параллельно. Такой подход значительно увеличивает производительность системы, но, с другой стороны, существенно усложняет решение проблем синхронизации. Адресное пространство Время Рис.
3.3. Многонитевые процессы в многопроцессорной системе Хотя оба средства (многонитевость и многопроцессорность) хорошо сочетаются друг с другом, их вполне можно использовать отдельно друг от друга. Многопроцессорные системы вполне пригодны для однонитевых приложе- 102 Глава 3.
Нити и легковесные процессы ний, так как в этом случае несколько процессов могут работать параллельно. Точно так же, имеются значительные преимущества в использовании многонитевых приложений на однопроцессорных системах. Если одна нить блокируется в ожидании окончания ввода-вывода или освобождения ресурса, другая нить может стать текущей, а приложение, таким образом, продолжит свое выполнение. Понятие нити более подходит для олицетворения встроенной одновременности выполнения в программе, нежели чем подгонки приложений под возможности многопроцессорных аппаратных архитектур. 3.1.3. Одновременность и параллельность Для того чтобы понять основные типы элементов нитей, необходимо сначала определить разницу между терминами «одновременность» (сопсцггепсу) и «параллельность» (рага1!е11зщ) 15). Параллельность многопроцессорного приложения — это достигнутая им степень параллельного выполнения, которая в любом случае будет ограничиваться количеством процессоров, физически доступных приложению.
Термин одновременность описывает максимальную степень параллельности, которую теоретически может достигать приложение с неограниченным количеством доступных процессоров. Эта степень зависит от того, как написано конкретное приложение, а также от количества нитей, которые могут выполняться одновременно, с доступными необходимыми им ресурсами. Одновременность может поддерживаться на уровне либо системы, либо отдельного приложения.
Ядро системы обеспечивает системную одновременность при помощи распознавания нескольких нитей внутри процесса (также называемых «горячими» нитями, <<ос г<веадв) и планирования их выполнения независимо. Ядро разделяет такие нити между доступными процессорами. Приложение может воспользоваться преимуществами системной одновременности даже на однопроцессорных системах, поскольку если одна из его нитей будет блокирована в ожидании события или освобождения ресурса, ядро может назначить на выполнение другую нить. Приложения могут обеспечивать прикладную одновременность через использование нитевых библиотек прикладного уровня. Такие нити, или сопрограммы (иногда называемые «холодными» нитями, со1с( сЬгеас(з), не распознаются ядром системы и должны управляться и планироваться самими приложениями.
Этот подход не дает настоящей одновременности или параллельности, поскольку такие нити не могут в действительности выполняться одновременно, но он является более естественной моделью вь<полнвния программы для приложений, требующих одновременности. Посредством использования неблокирующих системных вызовов приложение может одновременно поддерживать несколько взаимодействий в ходе своего выполнения. Использование прикладных нитей упрощает процесс выполнения программы, поскольку состояние таких взаимодействий считывается и размещается 3.2. Основные типы нитей 103 в локальных переменных каждой нити (в стеке каждой нити), и при этом не используется глобальная таблица переменных.
Каждая модель одновременной обработки имеет определенные ограничения, заложенные в ее основе. Нити используются как средства организации работы и как средства использования многопроцессорных систем. Нити ядра позволяют производить параллельные вычисления на многопроцессорных системах, но они не подходят для структурирования приложений. Например, серверному приложению может потребоваться создание тысяч отдельных нитей, каждая из которых обрабатывает один клиентский запрос. Нити ядра потребляют такие важные ресурсы, как физическую память (так как многие реализации 1ЛЧ1Х требуют постоянного хранения структур нитей в памяти); при этом, однако, они бесполезны для такого типа программ.
С другой стороны, возможности нитей прикладного уровня полезны только для структурирования приложений, но они не позволяют выполнять код параллельно. Во многих системах реализована модель двойной одновременности, которая совмещает в себе системную и прикладную одновременность. В этой модели нити процесса делятся на те, которые ядро распознает, и те, которые реализованы в библиотеках прикладного уровня и ядру не видимы. Прикладные нити позволяют синхронизировать одновременно исполняемые процедуры программы, не загружая систему дополнительными вызовами, и могут быть востребованы даже в системах, имеющих многонитевые ядра. Более того, уменьшение размера и функций ядра представляется хорошей дальнейшей стратегией развития 1ЛЧ1Х, и разделение функциональности по поддержке нитей между ядром и нитевыми библиотеками как раз отвечает этим требованиям.
3.2. Основные типы нитей Процесс представляет собой составную сущность, которую можно разделить на два основных компонента: набор нитей и набор ресурсов. Нить — это динамический обьект, в процессе представленный отдельной точкой управления и выполняющий последовательность команд, отсчитываемую от этой точки'. Ресурсы, включающие адресное пространство, открытые файлы, полномочия, квоты и т, д., используются всеми нитями процесса совместно. Каждая нить, кроме того, обладает собственными обьектами, такими как указатель команд, стек или контекст регистров. В традиционных системах ИЧ1Х процесс имеет единственную выполняющуюся нить.
Многонитевые системы расширяют эту концепцию, позволяя каждому процессу иметь более одной выполняющейся нити. ' Проще говоря, выполняемая параллельно в рамках вронесса часть вросраммьь — Прим. ред. 104 Глава 3. Нити и легковесные процессы Централизация ресурсов процесса имеет и некоторые недостатки. Представьте серверное приложение, которое производит различные файловые операции от имени удаленных клиентов. Для проверки прав доступа к файлам серверу при обслуживании клиента необходимо производить его идентификацию.
Для этого сервер запускается в системе с полномочиями суперпользователя и периодически вызывает зегц1д, зе1дЫ и зегдгоцрз для временного изменения своих полномочий в соответствии с клиентскими. Использование многонитевости для такого сервера, сделанное с целью повышения одновременности его функционирования, может привести к серьезным проблемам безопасности. Так как процесс обладает всего одним набором полномочий, в один момент времени он может работать только от одного клиента.
Таким образом, чтобы поддержать необходимый уровень безопасности, серверу приходится выполнять все системные вызовы последовательно, то есть в режиме выполнения одной-единственной нити. Существуют различные типы нитей, каждая нз которых обладает различными свойствами и применением. В этом разделе мы опишем три важнейших их типа: нити ядра, легковесные процессы и прикладные нити. 3.2.1. Нити ядра Нити ядра не требуют связи с каким-либо прикладным процессом.
Они создаются и уничтожаются ядром и внутри ядра по мере необходимости и отвечают за выполнение определенных функций. Такие нити используют совместно доступные области кода и глобальные данные ядра, но обладают собственным стеком в ядре. Они могут независимо назначаться на выполнение и используют стандартные механизмы синхронизации ядра, такие как з!еер() или вакецрО. Нити ядра применяются для выполнения таких операций, как асинхронный ввод-вывод. Вместо поддержки каких-либо специальных механизмов ядро просто создает новую нить для обработки запросов для каждой такой операции.
Запрос обрабатывается нитью синхронно, но для ядра представляется асинхронным событием. Нити ядра могут быть также использованы для обработки прерываний, подробнее об этом будет сказано в разделе 3.6.5. Нити ядра являются малозатратными при создании и дальнейшем использовании. Единственными используемыми ими ресурсами являются стек ядра и область, в которой сохраняется контекст регистров на период приостановки работы нити (необходимо также поддерживать некую структуру данных, хранящую информацию для назначения ее на выполнение и синхронизацию), Переключение контекста между нитями ядра также происходит быстро, так что нет необходимости обновлять отображение памяти. Применение нитей в ядре не является новым подходом.