Реализация понятия последовательного процесса в ОС


Для того чтобы операционная система могла управлять процессами, она должна располагать всей необходимой для этого информацией. С этой целью на каждый процесс заводится специальная информационная структура, называемая дескрип­тором процесса (описателем задачи, блоком управления задачей). В общем слу­чае дескриптор процесса содержит следующую информацию:

¨ идентификатор процесса (так называемый PID – process identificator);

¨ тип (или класс) процесса, который определяет для супервизора некоторые пра­вила предоставления ресурсов;

¨ приоритет процесса, в соответствии с которым супервизор предоставляет ре­сурсы. В рамках одного класса процессов в первую очередь обслуживаются более приоритетные процессы;

¨ переменную состояния, которая определяет, в каком состоянии находится процесс (готов к работе, в состоянии выполнения, ожидание устройства вво­да/вывода и т. д.);

¨ защищённую область памяти (или адрес такой зоны), в которой хранятся те­кущие значения регистров процессора, если процесс прерывается, не закон­чив работы. Эта информация называется контекстом задачи;

¨информацию о ресурсах, которыми процесс владеет и/или имеет право поль­зоваться (указатели на открытые файлы, информация о незавершенных опе­рациях ввода/вывода и т. п.);

¨ место (или его адрес) для организации общения с другими процессами;

¨ параметры времени запуска (момент времени, когда процесс должен активи­зироваться, и периодичность этой процедуры);

¨ в случае отсутствия системы управления файлами – адрес задачи на диске в её исходном состоянии и адрес на диске, куда она выгружается из оператив­ной памяти, если её вытесняет другая (для диск-резидентных задач, которые постоянно находятся во внешней памяти на системном магнитном диске и за­гружаются в оперативную память только на время выполнения).

Описатели задач, как правило, постоянно располагаются в оперативной памяти с целью ускорить работу супервизора, который организует их в списки (очере­ди) и отображает изменение состояния процесса перемещением соответствую­щего описателя из одного списка в другой. Для каждого состояния (за исклю­чением состояния выполнения для однопроцессорной системы) операционная система ведет соответствующий список задач, находящихся в этом состоянии. Однако для состояния ожидания может быть не один список, а столько, сколь­ко различных видов ресурсов могут вызывать состояние ожидания. Например, состояний ожидания завершения операции ввода/вывода может быть столько, сколько устройств ввода/вывода имеется в системе.

В некоторых операционных системах количество описателей определяется жест­ко и заранее (на этапе генерации варианта операционной системы или в конфи­гурационном файле, который используется при загрузке ОС), в других – по мере необходимости система может выделять участки памяти под новые описатели. Например, в OS/2 максимально возможное количество описателей задач опреде­ляется в конфигурационном файле CONFIG.SYS, а в Windows NT оно в явном виде не задается. Справедливости ради стоит заметить, что в упомянутом файле указывается количество не процессов, а именно задач, и под задачей в данном случае понимается как процесс, так и поток этого же процесса, называемый по­током или тредом (см. следующий раздел). Например, строка в файле CONFIG.SYS

THREADS=1024

указывает» что всего в системе может параллельно существовать и выполняться до 1024 задач, включая вычислительные процессы и их потоки.

В ОС реального времени чаще всего количество процессов фиксируется и, сле­довательно, целесообразно заранее определять (на этапе генерации или конфи­гурирования ОС) количество дескрипторов. Для использования таких ОС в ка­честве систем общего назначения (что сейчас встречается редко, а в недалеком прошлом достаточно часто в качестве вычислительных систем общего назначе­ния приобретали мини-ЭВМ и устанавливали на них ОС реального времени) обычно количество дескрипторов берется с некоторым запасом, и появление новой задачи связывается с заполнением этой информационной структуры. Поскольку дескрипторы процессов постоянно располагаются в оперативной памяти (с це­лью ускорить работу диспетчера), то их количество не должно быть очень боль­шим. При необходимости иметь большое количество задач один и тот же дескриптор может в разное время предоставляться для разных задач, но это сильно снижает скорость реагирования системы.

Для более эффективной обработки данных в системах реального времени целе­сообразно иметь постоянные задачи/полностью или частично всегда существую­щие в системе независимо от того, поступило на них требование или нет. Каждая постоянная задача обладает некоторой собственной областью оперативной памя­ти (ОЗУ-резидентные задачи) независимо от того, выполняется задача в данный момент или нет. Эта область, в частности, может использоваться для хранения данных, полученных задачей ранее. Данные могут храниться в ней и тогда, когда задача находится в состоянии ожидания или даже в состоянии бездействия.

Для аппаратной поддержки работы операционных систем с этими информаци­онными структурами (дескрипторами задач) в процессорах могут быть реали­зованы соответствующие механизмы. Так, например, в микропроцессорах Intel 80х86 (см. главу 3 «Особенности архитектуры микропроцессоров 180х86 для ор­ганизации мультипрограммных операционных систем»), начиная с 80286, имеет­ся специальный регистр TR (task register), указывающий местонахождение TSS (сегмента состояния задачи1, см. раздел «Новые системные регистры микропро­цессоров i80x86», глава 3), в котором при переключении с задачи на задачу авто­матически сохраняется содержимое регистров процессора [2, 22, 84]. Как прави­ло, в современных ОС для этих микропроцессоров дескриптор задачи включает в себя TSS. Другими словами, дескриптор задачи больше по размеру, чем TSS, и включает в себя такие традиционные поля, как идентификатор задачи, её имя, тип, приоритет и т. п.

Процессы и треды

Понятие процесса было введено для реализации идей мультипрограммирования. Напомним, в свое время различали термины «мультизадачность» и «мультипро­граммирование». Таким образом, для реализации «мультизадачности» в её ис­ходном толковании необходимо было тоже ввести соответствующую сущность. Такой сущностью и стали так называемые «легковесные» процессы, или, как их теперь преимущественно называют, – потоки или треды (нити)2. Рассмотрим эти понятия подробнее.

Когда говорят о процессах (process), то тем самым хотят отметить, что операци­онная система поддерживает их обособленность: у каждого процесса имеется свое виртуальное адресное пространство, каждому процессу назначаются свои ресур­сы – файлы, окна, семафоры и т. д. Такая обособленность нужна для того, чтобы защитить один процесс от другого, поскольку они, совместно используя все ре­сурсы вычислительной системы, конкурируют друг с другом. В общем случае процессы просто никак не связаны между собой и могут принадлежать даже раз­ным пользователям, разделяющим одну вычислительную систему. Другими сло­вами, в случае процессов ОС считает их совершенно несвязанными и независимыми. При этом именно ОС берет на себя роль арбитра в конкуренции между процессами по поводу ресурсов.

Однако желательно иметь ещё и возможность задействовать внутренний парал­лелизм, который может быть в самих процессах. Такой внутренний параллелизм встречается достаточно часто и его использование позволяет ускорить их реше­ние. Например, некоторые операции, выполняемые приложением, могут требо­вать для своего исполнения достаточно длительного использования центрального процессора. В этом случае при интерактивной работе с приложением пользова­тель вынужден долго ожидать завершения заказанной операции и не может управ­лять приложением до тех пор, пока операция не выполнится до самого конца. Такие ситуации встречаются достаточно часто, например, при обработке боль­ших изображений в графических редакторах. Если же программные модули, исполняющие такие длительные операции, оформлять в виде самостоятельных «подпроцессов» (легковесных или облегченных процессов – потоков, можно также воспользоваться термином задача), которые будут выполняться парал­лельно с другими «подпроцессами» (потоками, задачами), то у пользователя по­является возможность параллельно выполнять несколько операций в рамках од­ного приложения (процесса). Легковесными эти задачи называют потому, что операционная система не должна для них организовывать полноценную вирту­альную машину. Эти задачи не имеют своих собственных ресурсов, они развива­ются в том же виртуальном адресном пространстве, могут пользоваться теми же файлами, виртуальными устройствами и иными ресурсами, что и данный про­цесс. Единственное, что им необходимо иметь, – это процессорный ресурс. В од­нопроцессорной системе треды (задачи) разделяют между собой процессорное время так же, как это делают обычные процессы, а в мультипроцессорной систе­ме могут выполняться одновременно, если не встречают конкуренции из-за об­ращения к иным ресурсам.

Главное, что обеспечивает многопоточность, – это возможность параллельно вы­полнять несколько видов операций в одной прикладной программе. Параллель­ные вычисления (а, следовательно, и более эффективное использование ресур­сов центрального процессора, и меньшее суммарное время выполнения задач) теперь уже часто реализуется на уровне тредов, и программа, оформленная в виде нескольких тредов в рамках одного процесса, может быть выполнена быстрее за счёт параллельного выполнения её отдельных частей. Например, если электрон­ная таблица или текстовый процессор были разработаны с учётом возможностей многопоточной обработки, то пользователь может запросить пересчёт своего ра­бочего листа или слияние нескольких документов и одновременно продолжать заполнять таблицу или открывать для редактирования следующий документ.

Особенно эффективно можно использовать многопоточность для выполнения распределённых приложений; например, многопоточный сервер может параллельно выполнять запросы сразу нескольких клиентов. Как известно, операци­онная система OS/2 одной из первых среди ОС, используемых на ПК, ввела многопоточность. В середине девяностых годов для этой ОС было создано очень большое количество приложений, в которых использование механизмов много­поточной обработки реально приводило к существенно большей скорости вы­полнения вычислений.

Итак, сущность «поток» была введена для того, чтобы именно с помощью этих единиц распределять процессорное время между возможными работами. Сущ­ность «процесс» предполагает, что при диспетчеризации нужно учитывать все ресурсы, закрепленные за ним. А при манипулировании тредами можно менять только контекст задачи, если мы переключаемся с одной задачи на другую в рам­ках одного процесса. Все остальные вычислительные ресурсы при этом не затра­гиваются. Каждый процесс всегда состоит, по крайней мере, из одного потока, и только если имеется внутренний параллелизм, программист может «расще­пить» один тред на несколько параллельных.

Потребность в потоках (threads) возникла ещё на однопроцессорных вычисли­тельных системах, поскольку они позволяют организовать вычисления более эф­фективно. Для использования достоинств многопроцессорных систем с общей памятью треды уже просто необходимы, так как позволяют не только реально ускорить выполнение тех задач, которые допускают их естественное распаралле­ливание, но и загрузить процессорные элементы работой, чтобы они не простаи­вали. Заметим, однако, что желательно, чтобы можно было уменьшить взаимо­действие тредов между собой, ибо ускорение от одновременного выполнения параллельных потоков может быть сведено к минимуму из-за задержек синхро­низации и обмена данными.

Каждый тред выполняется строго последовательно и имеет свой собственный программный счётчик и стек. Треды, как и процессы, могут порождать треды-по­томки, поскольку любой процесс состоит, по крайней мере, из одного треда. По­добно традиционным процессам (то есть процессам, состоящим из одного треда), каждый тред может находится в одном из активных состояний. Пока один тред заблокирован (или просто находится в очерёди готовых к исполнению задач), другой тред того же процесса может выполняться. Треды разделяют процессор­ное время так же, как это делают обычные процессы, в соответствии с различны­ми вариантами диспетчеризации.

Как мы уже знаем, все треды имеют одно и то же виртуальное адресное про­странство своего процесса. Это означает, что они разделяют одни и те же гло­бальные переменные. Поскольку каждый тред может иметь доступ к каждому виртуальному адресу, один тред может использовать стек другого треда. Между потоками нет полной защиты, так как это, во-первых, невозможно, а во-вторых, не нужно. Все потоки одного процесса всегда решают общую задачу одного поль­зователя, и механизм потоков используется здесь для более быстрого решения задачи путем её распараллеливания. При этом программисту очень важно полу­чить в свое распоряжение удобные средства организации взаимодействия частей одной программы. Повторим, что кроме разделения адресного пространства, все треды разделяют также набор открытых файлов, используют общие устройства, выделенные процессу, имеют одни и те же наборы сигналов, семафоры и т. п. А что у тредов будет их собственным? Собственными являются программный счетчик, стек, рабочие регистры процессора, потоки-потомки, состояние.

Вследствие того, что треды, относящиеся к одному процессу, выполняются в од­ном и том же виртуальном адресном пространстве, между ними легко организо­вать тесное взаимодействие, в отличие от процессов, для которых нужны специ­альные механизмы обмена сообщениями и данными. Более того, программист, создающий многопоточное приложение, может заранее продумать работу мно­жества тредов процесса таким образом, чтобы они могли взаимодействовать наи­более выгодным способом, а не участвовать в конкуренции за предоставление ресурсов тогда, когда этого можно избежать.

Для того чтобы можно было эффективно организовать параллельное выполне­ние рассмотренных сущностей (процессов и тредов), в архитектуру современных процессоров включена возможность работать со специальной информационной структурой, описывающей ту или иную сущность. Для этого уже на уровне архи­тектуры микропроцессора используется понятие «задача» (task). Оно как бы объединяет в себе обычный и «легковесный» процессы. Это понятие и поддер­живаемая для него на уровне аппаратуры информационная структура позволяют в дальнейшем при разработке операционной системы построить соответствую­щие дескрипторы, как для процесса, так и для треда. Отличаться эти дескрипто­ры будут, прежде всего, тем, что дескриптор треда может хранить только контекст приостановленного вычислительного процесса, тогда как дескриптор процесса (process) должен уже содержать поля, описывающие тем или иным способом ре­сурсы, выделенные этому процессу. Другими словами, тот же task state segment (сегмент состояния задачи), подробно рассмотренный в разделе «Адресация в 32-разрядных микропроцессорах i80x86 при работе в защищённом режиме» гла­вы 3, используется как основа для дескриптора процесса. Каждый тред (в случае использования так называемой «плоской» модели памяти – см. раздел «Под­держка страничного способа организации виртуальной памяти», глава 3 – мо­жет быть оформлен в виде самостоятельного сегмента, что приводит к тому, что простая (не многопоточная) программа будет иметь всего один сегмент кода в виртуальном адресном пространстве.

В завершение можно привести несколько советов по использованию потоков при создании приложений, заимствованных из работы [55].

1 В случае использования однопроцессорной системы множество параллельных потоков часто не ускоряет работу приложения, поскольку в каждый отдельно взятый промежуток времени возможно выполнение только одного потока. Кроме того, чем больше у вас потоков, тем больше нагрузка на систему, по­траченная на переключение между ними. Если ваш проект имеет более двух постоянно работающих потоков, то такая мультизадачность не сделает про­грамму быстрее, если каждый из потоков не будет требовать частого ввода/ вывода.

2 Вначале нужно понять, для чего необходим поток. Поток, осуществляющий обработку, может помешать системе быстро реагировать на запросы ввода/ вывода. Потоки позволяют программе отзываться на просьбы пользователя и устройств, но при этом сильно загружать процессор. Потоки позволяют компьютеру одновременно обслуживать множество устройств, и созданный вами поток, отвечающий за обработку специфического устройства, в качестве минимума может потребовать столько времени, сколько системе необходимо для обработки запросов всех устройств.

3 Потокам можно назначить определенный приоритет для того, чтобы наиме­нее значимые процессы выполнялись в фоновом режиме. Это путь честного разделения ресурсов CPU1. Однако необходимо осознать тот факт, что про­цессор один на всех, а потоков много. Если в вашей программе главная про­цедура передаёт нечто для обработки в низкоприоритетный поток, то сама программа становится просто неуправляемой.

4 Потоки хорошо работают, когда они независимы. Но они начинают работать непродуктивно, если вынуждены часто синхронизироваться для доступа к об­щим ресурсам. Блокировка и критические секции отнюдь не увеличивают скорость работы системы, хотя без использования этих механизмов взаимо­действующие вычисления организовывать нельзя.

5 Помните, что память виртуальна. Механизм виртуальной памяти (см. раздел «Память и отображения, виртуальное адресное пространство», глава 2) сле­дит за тем, какая часть виртуального адресного пространства должна нахо­диться в оперативной памяти, а какая должна быть сброшена в файл подкачки. Потоки усложняют ситуацию, если они обращаются в одно и то же время к разным адресам виртуального адресного пространства приложения. Это зна­чительно увеличивает нагрузку на систему, особенно при небольшом объёме кэш-памяти. Помните, что реально память не всегда «свободна», как это пи­шут в информационных «окошках» «О системе». Всегда отождествляйте дос­туп к памяти с доступом к файлу на диске и создавайте приложение с учётом вышесказанного.

6 Всякий раз, когда какой-либо из ваших потоков пытается воспользоваться общим ресурсом вычислительного процесса, которому он принадлежит, вы обязаны тем или иным образом легализовать и защитить свою деятельность. Хорошим средством для этого являются критические секции, семафоры и очерёди сообщений. Если вы протестировали свое приложение и не обнаружили ошибок синхронизации, то это ещё не значит, что их там нет. Пользователь может создать самые непредсказуемые ситуации. Это очень ответственный момент в разработке многопоточных приложений.

7 Не возлагайте на поток несколько функций. Сложные функциональные отно­шения затрудняют понимание общей структуры приложения, его алгоритм. Чем проще и менее многозначна каждая из рассматриваемых ситуаций, тем больше вероятность, что ошибок удастся избежать.

Прерывания

Прерывания представляют собой механизм, позволяющий координировать па­раллельное функционирование отдельных устройств вычислительной системы и реагировать на особые состояния, возникающие при работе процессора. Таким образом, прерывание – это принудительная передача управления от выполняе­мой программы к системе (а через неё – к соответствующей программе обработ­ки прерывания), происходящая при возникновении определенного события.

Идея прерываний была предложена в середине 50-х годов и можно без преувели­чения сказать, что она внесла наиболее весомый вклад в развитие вычислитель­ной техники. Основная цель введения прерываний – реализация асинхронного режима работы и распараллеливание работы отдельных устройств вычислитель­ного комплекса.

Механизм прерываний реализуется аппаратно-программными средствами. Струк­туры систем прерывания (в зависимости от аппаратной архитектуры) могут быть самыми разными, но все они имеют одну общую особенность – прерывание не­пременно влечет за собой изменение порядка выполнения команд процессором.

Механизм обработки прерываний независимо от архитектуры вычислительной системы включает следующие элементы:

1 Установление факта прерывания (прием сигнала на прерывание) и иденти­фикация прерывания (в операционных системах иногда осуществляется по­вторно, на шаге 4).

2 Запоминание состояния прерванного процесса. Состояние процесса определяется, прежде всего, значением счетчика команд (адресом следующей команды, который, например, в i80x86 определяется регистрами CS и IP – указателем команды [2, 22, 84]), содержимым регистров процессора и может включать также спецификацию режима (например, режим пользовательский или при­вилегированный) и другую информацию.

3 Управление аппаратно передаётся подпрограмме обработки прерывания. В про­стейшем случае в счётчик команд заносится начальный адрес подпрограммы обработки прерываний, а в соответствующие регистры – информация из сло­ва состояния. В более развитых процессорах, например в том же i80286 и по­следующих 32-битовых микропроцессорах, начиная с i80386, осуществляется достаточно сложная процедура определения начального адреса соответствую­щей подпрограммы обработки прерывания и не менее сложная процедура инициализации рабочих регистров процессора (см. раздел «Система прерыва­ний 32-разрядных микропроцессоров i80x86», глава 3).

4 Сохранение информации о прерванной программе, которую не удалось спа­сти на шаге 2 с помощью действий аппаратуры. В некоторых вычислитель­ных системах предусматривается запоминание довольно большого объёма информации о состоянии прерванного процесса.

5 Обработка прерывания. Эта работа может быть выполнена той же подпро­граммой, которой было передано управление на шаге 3, но в ОС чаще всего она реализуется путем последующего вызова соответствующей подпрограммы.

6 Восстановление информации, относящейся к прерванному процессу (этап, обратный шагу 4).

7. Возврат в прерванную программу.

Шаги 1-3 реализуются аппаратно, а шаги 4-7 – программно.

На рис. 1.4 показано, что при возникновении запроса на прерывание естествен­ный ход вычислений нарушается и управление передаётся программе обработ­ки возникшего прерывания. При этом средствами аппаратуры сохраняется (как правило, с помощью механизмов стековой памяти) адрес той команды, с которой следует продолжить выполнение прерванной программы. После выполнения про­граммы обработки прерывания управление возвращается прерванной ранее про­грамме посредством занесения в указатель команд сохранённого адреса команды. Однако такая схема используется только в самых простых программных средах. В мультипрограммных операционных системах обработка прерываний происхо­дит по более сложным схемам, о чём будет более подробно написано ниже.

 
 

Рис. 1.4. Обработка прерывания

Итак, главные функции механизма прерываний:

¨ распознавание или классификация прерываний;

¨ передача управления соответственно обработчику прерываний;

¨ корректное возвращение к прерванной программе.

Переход от прерываемой программы к обработчику и обратно должен выпол­няться как можно быстрей. Одним из быстрых методов является использование таблицы, содержащей перечень всех допустимых для компьютера прерываний и адреса соответствующих обработчиков. Для корректного возвращения к пре­рванной программе перед передачей управления обработчику прерываний со­держимое регистров процессора запоминается либо в памяти с прямым досту­пом, либо в системном стеке – system stack.

Прерывания, возникающие при работе вычислительной системы, можно разде­лить на два основных класса: внешние (их иногда называют асинхронными) и внутренние (синхронные).

Внешние прерывания вызываются асинхронными событиями, которые происхо­дят вне прерываемого процесса, например:

¨ прерывания от таймера;

¨ прерывания от внешних устройств (прерывания по вводу/выводу);

¨ прерывания по нарушению питания;

¨ прерывания с пульта оператора вычислительной системы;

¨ прерывания от другого процессора или другой вычислительной системы.

Внутренние прерывания вызываются событиями, которые связаны с работой про­цессора и являются синхронными с его операциями. Примерами являются сле­дующие запросы на прерывания:

¨ при нарушении адресации (в адресной части выполняемой команды указан запрещённый или несуществующий адрес, обращение к отсутствующему сег­менту или странице при организации механизмов виртуальной памяти);

¨ при наличии в поле кода операции незадействованной двоичной комбинации;

¨ при делении на нуль;

¨ при переполнении или исчезновении порядка;

¨ при обнаружении ошибок чётности, ошибок в работе различных устройств аппаратуры средствами контроля.

Могут ещё существовать прерывания при обращении к супервизору ОС – в не­которых компьютерах часть команд может использовать только ОС, а не пользо­ватели. Соответственно в аппаратуре предусмотрены различные режимы работы, и пользовательские программы выполняются в режиме, в котором эти привиле­гированные команды не исполняются. При попытке использовать команду, запрещённую в данном режиме, происходит внутреннее прерывание и управление передаётся супервизору ОС. К привилегированным командам относятся и ко­манды переключения режима работа центрального процессора.

Наконец, существуют собственно программные прерывания. Эти прерывания про­исходят по соответствующей команде прерывания, то есть по этой команде про­цессор осуществляет практически те же действия, что и при обычных внутрен­них прерываниях. Данный механизм был специально введен для того, чтобы переключение на системные программные модули происходило не просто как переход в подпрограмму, а точно таким же образом, как и обычное прерывание. Этим обеспечивается автоматическое переключение процессора в привилегиро­ванный режим с возможностью исполнения любых команд.

Сигналы, вызывающие прерывания, формируются вне процессора или в самом процессоре; они могут возникать одновременно. Выбор одного из них для обра­ботки осуществляется на основе приоритетов, приписанных каждому типу пре­рывания. Очевидно, что прерывания от схем контроля процессора должны обла­дать наивысшим приоритетом (если аппаратура работает неправильно, то не имеет смысла продолжать обработку информации). На рис.1.5 изображен обыч­ный порядок (приоритеты) обработки прерываний в зависимости от типа преры­ваний. Учет приоритета может быть встроен в технические средства, а также определяться операционной системой, то есть кроме аппаратно реализованных приоритетов прерывания большинство вычислительных машин и комплексов допускают программно-аппаратное управление порядком обработки сигналов прерывания. Второй способ, дополняя первый, позволяет применять различные дисциплины обслуживания прерываний.

Наличие сигнала прерывания не обязательно должно вызывать прерывание исполняющейся программы. Процессор может обладать средствами защиты от прерываний: отключение системы прерываний, маскирование (запрет) отдель­ных сигналов прерывания. Программное управление этими средствами (сущест­вуют специальные команда для управления работой системы прерываний) по­зволяет операционной системе регулировать обработку сигналов прерывания, заставляя процессор обрабатывать их сразу по приходу, откладывать их обработ­ку на некоторое время или полностью игнорировать. Обычно операция прерыва­ния выполняется только после завершения выполнения текущей команды. По­скольку сигналы прерывания возникают в произвольные моменты времени, то на момент прерывания может существовать несколько сигналов прерывания, ко­торые могут быть обработаны только последовательно. Чтобы обработать сигна­лы прерывания в разумном порядке им (как уже отмечалось) присваиваются приоритеты. Сигнал с более высоким приоритетом обрабатывается в первую очередь, обработка остальных сигналов прерывания откладывается.

 
 

Рис. 1.5. Распределение прерываний по уровням приоритета

Программное управление специальными регистрами маски (маскирование сиг­налов прерывания) позволяет реализовать различные дисциплины обслужива­ния:

¨ с относительными приоритетами, то есть обслуживание не прерывается даже при наличии запросов с более высокими приоритетами. После окончания об­служивания данного запроса обслуживается запрос с наивысшим приоритетом. Для организации такой дисциплины необходимо в программе обслуживания данного запроса наложить маски на все остальные сигналы прерывания или просто отключить систему прерываний;

¨ с абсолютными приоритетами, то есть всегда обслуживается прерывание с наивысшим приоритетом. Для реализации этого режима необходимо на вре­мя обработки прерывания замаскировать все запросы с более низким приори­тетом. При этом возможно многоуровневое прерывание, то есть прерывание программ обработки прерываний. Число уровней прерывания в этом режиме изменяется и зависит от приоритета запроса;

¨ по принципу стека, или, как иногда говорят, по дисциплине LCFS (last come first served – последним пришёл – первым обслужен), то есть запросы с более низким приоритетом могут прерывать обработку прерывания с более вы­соким приоритетом. Дли этого необходимо не накладывать маски ни на один сигнал прерывания и не выключать систему прерываний.

Следует особо отметить, что для правильной реализации последних двух дисци­плин нужно обеспечить полное маскирование системы прерываний при выпол­нении шагов 1-4 и 6-7. Это необходимо для того, чтобы не потерять запрос и правильно его обслужить. Многоуровневое прерывание должно происходить на этапе собственно обработки прерывания, а не на этапе перехода с одного процес­са на другой.

Управление ходом выполнения задач со стороны ОС заключается в организации реакций на прерывания, в организации обмена информацией (данными и про­граммами), предоставлении необходимых ресурсов, в динамике выполнения за­дачи и в организации сервиса. Причины прерываний определяет ОС (модуль, который называют супервизором прерываний), она же и выполняет действия, необходимые при данном прерывании и в данной ситуации. Поэтому в состав любой ОС реального времени прежде всего входят программы управления сис­темой прерываний, контроля состояний задач и событий, синхронизации задач, средства распределения памяти и управления ею, а уже потом средства органи­зации данных (с помощью файловых систем и т. д.). Следует, однако, заметить, что современная ОС реального времени должна вносить в аппаратно-программ­ный комплекс нечто большее, нежели просто обеспечение быстрой реакции на прерывания.

Как мы уже знаем, при появлении запроса на прерывание система прерываний идентифицирует сигнал и, если прерывания разрешены, управление передаётся на соответствующую подпрограмму обработки. Из рис.1.4 видно, что в подпро­грамме обработки прерывания имеются две служебные секции. Это – первая секция, в которой осуществляется сохранение контекста прерванной задачи, ко­торый не смог быть сохранен на 2-м шаге, и последняя, заключительная секция, в которой, наоборот, осуществляется восстановление контекста. Для того чтобы система прерываний не среагировала повторно на сигнал запроса на прерывание, она обычно автоматически «закрывает» (отключает) прерывания, поэтому необ­ходимо потом в подпрограмме обработки прерываний вновь включать систему прерываний. Установка рассмотренных режимов обработки прерываний (с отно­сительными и абсолютными приоритетами, и по правилу LCFS) осуществляется в конце первой секции подпрограммы обработки. Таким образом, на время вы­полнения центральной секции (в случае работы в режимах с абсолютными при­оритетами и по дисциплине LCFS) прерывания разрешены. На время работы заключительной секции подпрограммы обработки система прерываний должна быть отключена и после восстановления контекста вновь включена. Поскольку эти действия необходимо выполнять практически в каждой подпрограмме обра­ботки прерываний, во многих операционных системах первые секции подпро­грамм обработки прерываний выделяются в специальный системный программ­ный модуль, называемый супервизором прерываний

Супервизор прерываний прежде всего сохраняет в дескрипторе текущей задачи рабочие регистры процессора, определяющие контекст прерываемого вычисли­тельного процесса. Далее он определяет ту подпрограмму, которая должна выполнить действия, связанные с обслуживанием настоящего (текущего) запроса на прерывание. Наконец, перед тем как передать управление этой подпрограмме, супервизор прерываний устанавливает необходимый режим обработки прерыва­ния. После выполнения подпрограммы обработки прерывания управление вновь передаётся супервизору, на этот раз уже на тот модуль, который занимается дис­петчеризацией задач (см. раздел «Качество диспетчеризации и гарантии обслу­живания», глава 2). И уже диспетчер задач, в свою очередь, в соответствии с принятым режимом распределения процессорного времени (между выполняю­щимися процессами) восстановит контекст той задачи, которой будет решено выделить процессор. Рассмотренная нами схема проиллюстрирована на рис. 1.6.

 

 
 

Рис. 1.6. Обработка прерывания при участии супервизоров ОС

Как мы видим из рис. 1.6, здесь нет непосредственного возврата в прерванную ранее программу непосредственно из самой подпрограммы обработки прерыва­ния. Для прямого непосредственного возврата достаточно адрес возврата сохра­нить в стеке, что и делает аппаратура процессора. При этом стек легко обеспе­чивает возможность возврата в случае вложенных прерываний, поскольку он всегда реализует дисциплину LCFS (last come – first served).

Однако если бы контекст процессов сохранялся просто в стеке, как это обычно реализуется аппаратурой, а не в описанных выше дескрипторах задач, то у нас не было бы возможности гибко подходить к выбору той задачи, которой нужно пе­редать процессор после завершения работы подпрограммы обработки прерыва­ния. Естественно, что это только общий принцип. В конкретных процессорах и в конкретных ОС могут существовать некоторые отступления от рассмотренной схемы и/или дополнения к ней. Например, в современных процессорах часто имеются специальные аппаратные возможности для сохранения контекста прерываемого процесса непосредственно в его дескрипторе, то есть дескриптор про­цесса (по крайней мере, его часть) становится структурой данных, которую под­держивает аппаратура.

Для полного понимания принципов создания и механизмов реализации рассмат­риваемых далее современных ОС необходимо знать архитектуру персональных компьютеров и, в частности, особенности системы прерывания. Этот вопрос бо­лее подробно рассмотрен в главе 4 «Управление вводом/выводом и файловые системы», посвящённом архитектуре микропроцессоров i80x86.

 



Дата добавления: 2022-02-05; просмотров: 391;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.044 сек.