Ю. Вахалия - UNIX изнутри (2003) (1114670), страница 29
Текст из файла (страница 29)
По умолчанию библиотека создает для каждого процесса набор 1ЛйгР и мультиплексирует в него все прикладные нити. Размер такого набора зависит от количества процессоров и прикладных нитей. Разработчик приложения волен изменить начальные установки и самостоятельно указать количество создаваемых легковесных процессов. Он также вправе потребовать от системы назначения 1.%'Р какой-то определенной нити. Таким образом, процесс может обладать прикладными нитями двух типов: свободными (связанными с единственным 1ЛЪ'Р) нитями и несвязанными, разделяющими общий набор легковесных процессов (рис.
3.8). Сплетенные нити Свободные нити , Адресное пространство Рис. 3.8. Схема процесса е системе Зо!алз 2.х Мультиплексирование большого количества нитей в небольшое число 1.Ъ'Р дает возможность одновременной работы при достаточно низких затратах. Например, в оконной системе каждый обьект (диалоговое окно, меню, пиктограмма и т. д.) может быть представлен в виде нити. В один момент времени обычно активно лишь некоторое количество окон, следовательно, З.б.
Многонитевость в Зо!аг1в и ВЧй4 125 только эти нити должны поддерживаться 1 ЮР. Количество легковесных процессов определяет максимальную параллельность, которую может достигать приложение (как минимум равную количеству имеющихся процессоров). Оно также ограничивает количество одновременно имеющихся блокированных операций в процессе. В некоторых случаях превышение количества нитей над ЫЧР является недостатком. Например, при вычислении произведения двух двухмерных массивов мы могли бы вычислять каждый элемент результирующего массива в отдельной нити. Если количество процессоров невелико, то этот метод, вероятно, окажется непродуктивным, так как библиотека может терять много времени на переключение контекста между нитями. Более эффективным решением может стать создание одной нити для каждой строки вычисляемого массива и привязка каждой нити к отдельному 1.ЮР.
Использование связанных и несвязанных прикладных нитей в одном приложении бывает весьма эффективным в тех случаях, когда требуется какая-либо обработка, время выполнения которой критично. Такая обработка может быть выполнена нитями, связанными с 1.ЮР, которым в расписании назначен приоритет реального времени. При этом другие нити отвечают за фоновые операции, имеющие более низкий приоритет.
В приведенном ранее примере оконной системы нити реального времени могут использоваться для обработки движений мыши, так как их результаты должны немедленно появляться на экране монитора'. 3.6.4. Реализация прикладных нитей Каждая прикладная нить должна поддерживать информацию следующего содержания: + Идентификатор нити (Йгеаг( 1Э). Позволяет нитям взаимодействовать друг с другом в рамках процесса при помощи сигналов и прочих средств. + Сохраненное состояние регистров (зачес1 ген(згег зсасе). Содержит указатель команд и указатель стека.
+ Стек в приложении (цзег згас1с). Каждая нить обладает своим собственным стеком, размещаемым при помощи библиотеки. Ядро системы не знает о существовании подобных стеков. + Маска сигналов (з)ппа! шаз1с). Каждая нить может обладать собственной маской сигналов. Когда приходит сигнал, библиотека доведет его до соответствующей нити, исходя из информации, содержащейся в масках всех нитей, ' Неудачный пример. Обработана (не отображение на уровне драйвера) движений мыши в развитых графических оболочках (1ЛЧ1Х, ЪЧпдоч з, 08/2 — для 1оге1 80х86) возможна только после выборки сообщений из общей очереди, что несмотря на все приоритеты не позволяет получить немедленные результаты.
Можно наблюдать иллюстрацию сказанного при высокой загрузке процессора. Представлять каждый оконный обьект в виде нити также нецелесообразно. — Примеч. ред. 126 Глава 3. Нити и легковесные процессы + Приоритет (рг!ог!Гу). Прикладная нить имеет приоритет внутри процесса, который используется планировщиком нитей. Ядро системы не обладает информацией о таких приоритетах и производит планирование выполнения только для 1ЛЧР, содержащих эти нити. + Локальная область хранения нити (гйгеад 1гегпе1 ьтогайе). Каждой нити позволено иметь некоторую собственную область для хранения данных (управляемую библиотекой) с целью поддержки реентерабельных версий интерфейсов библиотеки С !!3!.
Например, многие функции библиотеки С возвращают код ошибки в глобальную переменную еггпо. Если одну из таких функций вызовут одновременно несколько нитей, то это может привести к хаосу. Для предупреждения подобных проблем многонитевые библиотеки помещают значения еггпо в локальную область хранения нити !20!. Нити используют средства синхронизации, предоставляемые библиотекой, которые похожи на аналогичные средства ядра (условные переменные, семафоры и т. д.).
Система Бо!аг!з позволяет нитям разных процессов синхронизироваться друг с другом при помощи переменных синхронизации, помещаемых в совместно используемый участок памяти. Такие переменные могут также быть размещены в файлах, а доступ к ним может быть организован при помощи механизма отображения файла пипар. Такой подход позволяет объектам синхронизации иметь время жизни большее, чем у создавшего их процесса, и, следовательно, задействовать эти переменные для синхронизации нитей разных процессов.
3.6.5. Обработка прерываний Обработчики прерываний часто манипулируют данными, используемыми также и ядром системы. Это требует синхронизации доступа к разделяемым данным. В традиционных системах П ПХ ядро обеспечивает ее, повышая уровень приоритета прерываний (!р1) для блокирования тех прерываний, которые в состоянии получить доступ к таким данным. Часто объекты защищаются от прерываний, хотя обращение к ним со стороны каких-либо прерываний малореально. Например, очередь спящих процессов должна быть защищена от прерываний, хотя большинству из них нет необходимости обращаться к этой очереди. Эта модель обладает несколькими существенными недостатками.
Во многих системах процедура увеличения или уменыпения уровня 1р! является весьма затратной и требует выполнения нескольких инструкций. Прерывания представляют собой важные и обычно экстренные события, поэтому их блокирование уменьшает производительность системы в большинстве случаев. В многопроцессорных системах эта проблема еще актуальнее, так как ядру 3,6. Многонитевость в Ьо!апз и ЬЧН4 127 системы приходится защищать намного большее количество объектов и обычно приходится блокировать прерывания на всех имеющихся процессорах.
В операционной системе Бо!аг!з традиционная модель прерываний и синхронизации заменена новой технологией, увеличивающей производительность, в первую очередь, на многопроцессорных системах (11!, !17!. Новая модель не использует уровни !р! для защиты от прерываний. Вместо этого применяется набор различных объектов ядра для осуществления синхронизации, таких как взаимные исключения или семафоры. Для обработки прерываний используется набор нитей ядра.
Такие нити прерываний могут быть созданы «на лету»; им будет назначен более высокий приоритет выполнения, чем у любых других существующих нитей. Нити прерываний используют те же основные элементы синхронизации, что и любые другие нити, и, следовательно,могут блокироваться в тех случаях, когда необходимый им ресурс занят другой нитью.
Ядро блокирует обработку прерываний только при возникновении малого количества исключительных ситуаций, например при попытке освободитыпогех, защищающий очередь спящих процессов. Хотя создание нитей ядра является относительно несложной процедурой, однако организация новой нити для каждого прерывания слишком накладна. Ядро содержит набор предварительно выделенных и частично инициализированных нитей. По умолчанию такой набор состоит из количества нитей, равного количеству уровней прерываний помноженному на количество процессоров плюс егце одна общая системная нить для таймера. Поскольку каждая нить требует около 8 Кбайт для хранения стека и данных, весь набор занимает значительное количество памяти.
На системах, обладаюгцих небольшим объемом памяти, имеет смысл уменьшить количество нитей в наборе, так как ситуация, когда необходимо будет одновременно обрабатывать все прерывания,маловероятна. На рис. 3.9 показана схема обработки прерываний в системе 8о!аг!з. Нить Н1 выполняется на процессоре П1 в тот момент времени, когда он получает прерывание. Обработчик прерывания в первую очередь поднимает уровень !р! для предотвращения дальнейших прерываний того же или более низкого уровня (предохраняющая семантика системы П)Ч!Х).
Далее происходит выделение нити прерывания Н2 из набора нитей и переключение контекста на нее. Пока нить Н2 выполняется, Н1 остается прикрепленной (р!ппед). Это означает, что она не может выполняться на другом процессоре. После завершения Н2 происходит обратное переключение контекста к нити Н1, которая затем продолжает свою работу. Нить прерываний Н2 выполняется без полной инициализации.
Это означает, что она не является полноценной нитью и не может быть вытеснена. Инициализация завершается только в том случае, если нить имеет причину для блокирования. Тогда она сохраняет свое состояние и становится независимой нитью, выполняющейся на любом свободном процессоре. Если нить Н2 заблокируется, управление возвратится к Н1, таким образом откреп- 128 Глава 3.