Ю. Вахалия - UNIX изнутри (2003) (1114670), страница 24
Текст из файла (страница 24)
Такие системные процессы, как радедаетол, в традиционных системах (ЛЧ(Х функционально 3.2. Основные типы нитей 106 похожи на нити ядра. Процессы-демоны, наподобие п(зц (сервер Ыегцог1с Ие Бузсет), запускаются на прикладном уровне, однако после запуска полностью выполняются в ядре. После входа в режим ядра их прикладной контекст становится ненужным. Они также эквивалентны нитям ядра.
Так как в традиционнвях системах 1ЛЧ1Х отсутствовало понятие разделения применительно к представлению нитей ядра, такие процессы были вынуждены «таскать» за собою ненужный багаж, присущий традиционным процессам, в виде таких структур, как ргос и цзег. Многонитевые системы позволили реализовать демоны намного проще в качестве нитей ядра. 3.2.2. Легковесные процессы Легковесный à — т Нить; — -, Адресное 1л) процесс > ядра .' пространство ® Процесс Рис. 3.4.
Легковесные процессы Легковесный процесс (или 1.ЮР, 11фгтче1ййг ргосекз) — это прикладная нить, поддерживаемая ядром. 1.ЖР является абстракцией высокого уровня, основанной на нитях ядра. Каждый процесс может иметь один или более 1'ьтгР, любой из которых поддерживается отдельной нитью ядра (рис. 3.4). Легковесные процессы планируются на выполнение независимо от процесса, но совместно разделяют адресное пространство и другие ресурсы процесса. Они обладают возможностью производить системные вызовы и блокироваться в ожидании окончания ввода-вывода или освобождения ресурсов. На многопроцессорных системах процесс в состоянии использовать преимущества настоящей параллельной работы, так как каждый 1.ЖР может выполняться на отдельном процессоре. Однако даже на однопроцессорных системах применение 1.'тьгР дает существенные преимущества, поскольку при ожидании ресурсов или окончания ввода-вывода блокируется не весь процесс в целом, а только отдельные 1ЛЪ'Р.
106 Глава 3. Нити и легковесные процессы Кроме стека ядра и контекста регистров легковесному процессу необходимо поддерживать некоторое состояние задачи, что в первую очередь включает контекст регистров задачи, который необходимо сохранять перед тем, как обслуживание 1ЮР будет прервано. Несмотря на то что каждый ЕЮР ассоциирован с нитью ядра, некоторые нити ядра могут выполнять системные задачи и не относиться к какому-либо ЕЪ'Р. Многонитевые процессы применяются прежде всего в тех случаях, когда каждая нить являегся полностью независимой и редко взаимодействует с другими нитями. Код приложения является полностью вытесняемым, при этом все ЕЪЪ'Р в процессе совместно используют одно и то же адресное пространство процесса. Если доступ к каким-либо данным производится одновременно несколькими ЕЫР, необходимо обеспечить некоторую синхронизацию доступа, Для этого ядро системы предоставляет средства блокировки разделяемых переменных, при попытке прохождения в которые 1ЛЪ'Р будут блокированы.
Такими средствами являются взаимные исключения (тигиаг' вхсгияоп, или тигвх), атрибуты защиты, или защелки ((осях), семафоры и условные переменные, которые будут более подробно рассмотрены в главе 7. Рассказывая о легковесных процессах, необходимо также упомянуть и об их ограничениях. Многие операции над такими процессами, например создание, уничтожение и синхронизация, требуют применения системных вызовов. Однако системные вызовы по ряду причин являются весьма затратными операциями. Каждый вызов требует двух переключений режима: сначала из режима задачи в режим ядра и обратное переключение после завершения работы функции.
При каждом переключении режима ЕЪ'Р пересекает гранииу защиты (ргогесг1оп Ьоцпдагу). Ядро должно скопировать все параметры системного вызова из пространства задачи в пространство ядра и привести их при необходимости в корректное состояние для защиты обработчиков этих вызовов от вредоносных или некорректно работаюших процессов. При возврате из системного вызова ядро должно скопировать данные обратно в пространство задачи. Когда легковесным процессам необходимо часто пользоваться разделяемыми данными, затраты на синхронизацию могут свести на нет увеличение производительности от их применения.
Многие многопроцессорные системы поддерживают блокировку ресурсов, которая может быть активизирована из прикладного уровня при условии отсутствия удержания данного ресурса другой нитью (18~. Если нити необходим ресурс, который в данный момент недоступен, она может выполнить цикл активного ожидания (Ьцзу-ъай) его освобождения без вмешательства ядра. Такие циклы подходят только для доступа к тем ресурсам, которые занимаются на короткие промежутки времени, в иных случаях необходимо блокирование нити. Блокирование ь)УР требует вмешательства ядра и вследствие этого является затратной процедурой.
3.2. Основные типы нитей 107 Каждый легковесный процесс потребляет значительные ресурсы ядра, включая физическую память, отводимую под стек ядра. По этой причине система не может поддерживать большое количество 1.ЮР. Более того, так как система имеет единую реализацию 1ЛУР, такие процессы должны обладать достаточной универсальностью для поддержки наиболее типичных приложений. Таким образом, они могут содержать в себе такие свойства, которые окажутся ненужными большинству приложений. Применение 1.ТУР совершенно не подходит для приложений, использующих большое количество нитей или часто создающих и уничтожающих их. Наконец, легковесные процессы должны планироваться на выполнение ядром. Приложения, которым необходимо часто передавать управление от одной нити к другой, не могут делать это так легко, используя 1.ЮР.
Применение легковесных процессов также способно повлечь некоторые неожиданные последствия, например, приложение имеет возможность монополизировать использование процессора, создав большое количество МУР. Подводя итоги, скажем, что хотя ядро системы предоставляет механизмы создания, синхронизации и обработки легковесных процессов, за их правильное применение отвечает программист.
Многим приложениям больше подходит реализация на прикладных нитях, описанных в следующем разделе. ПРИМЕЧАНИЕ Термин «легковесные процессы» (ИУР) позаимствован из терминологии систем ЗНН4/МР и Зо!апз 2.х. Возможно, это не совсем точно, так как после появления четвертой версии Вцп08 термин ИМР используется для обозначения прикладных нитей, описание которых вы мо.кете увидеть в следующей главе. Однако в этой книге мы продолжим использование термина УИР для обозначения прикладных нитей, поддерживаемых ядром.
В некоторых системах применяется термин «виртуальный процессор., который имеет то же значение, что и ьУУР'. 3.2.3. Прикладные нити Существует возможность поддержки нитей полностью на прикладном уровне, при этом ядру об их существовании ничего известно не будет. Указанная возможность реализована в таких библиотечных пакетах, как С-йгеасЬ системы МасЬ и рйгеа Ь стандарта РОЯ1Х. Эти библиотеки содержат все необходимые функции для создания, синхронизации, планирования и обработки нитей без какой-либо специальной помощи ядра.
Функционирование таких нитей не требует обслуживания ядром и вследствие этого является необычайно быстрым'. На рис. 3.5, а представлена схема функционирования прикладных нитей. ' Иногда легковесные процессы называют еще тяжеловесными нитями, — Прим. ред. г Большинство нитевых библиотек требуют вмешательства ядра для поддержки средств асинхронною ввода-вывода. 108 Глава 3.
Нити и легковесные процессы Рисунок 3.5, б иллюстрирует совместное использование прикладных нитей и легковесных процессов, вместе создающих мощную среду выполнения программы. Ядро распознает, планирует на выполнение и управляет ЕЖР. Библиотеки прикладного уровня мультиплексируют прикладные нити в ЕЖР и предоставляют возможности для межнитевого планирования, переключения контекста и синхронизации без участия ядра. Получается, что библиотека функционирует как миниатюрное ядро для тех нитей, которыми она управляет.
Реализация прикладных нитей возможна по причине того, что прикладной контекст нити может сохраняться и восстанавливаться без вмешательства ядра. Каждая прикладная нить обладает собственным стеком в адресном пространстве процесса, областью для хранения контекста регистров прикладного уровня и другой важной информации, такой как маски сигналов. Библиотека планирует выполнение и переключает контекст между прикладными нитями, сохраняя стек и состояние регистров текущей нити и загружая стек и состояние регистров следующей по расписанию нити. Процесс 1 Процесс 3 Процесс 2 ДН П, Процесс ДЛ нить 3 р ~ 3 процесс .' пространство Рис.
3.5. Применение пользовательских нитей; а — прикладные нити обычных процессов; б — мультиплексирование прикладных нитей Ядро системы отвечает за переключение процессов, так как только оно обладает привилегиями, необходимыми для изменения регистров управления памятью (регистров ММП). Поэтому прикладные нити не являются по- 3.2. Основные типы нитей 109 настоящему планируемыми задачами, и ядро ничего не знает о них. Ядро просто планирует выполнение процесса (или 1Ъу'Р), содержащего в себе прикладные нити, который, в свою очередь, использует библиотечные функции для планирования выполнения своих нитей. Если процесс или 1.'ЖР вытеснен кем-то, то той же участи подвергаются и все его нити.
Точно так же, если нить делает блокирующий системный вызов, то он заблокирует и 1.%Р этой нити. Соответственно, если процесс обладает всего одним 1ЖР (или если прикладные нити реализованы на однонитевой системе), будут заблокированы все его нити. Нитевая библиотека также включает в себя объекты синхронизации, обеспечивающие защиту совместно используемых структур данных. Такие объекты обычно содержат переменную блокировки (например, семафор) и очередь нитей, заблокированных по ней. Нити должны проверить блокировку перед тем, как начать доступ к защищенной структуре данных.