Государственный комитет РФ по высшему образованию _________________ Санкт-Петербургский государственный электротехнический университет ______________________________________________________ Методические указания к лабораторным работам по дисциплине "Операционные среды АСОИУ" Санкт-Петербург 1996 ББК 3 986 УДК 681.518.3:681.3.06 Методические указания к лабораторным работам по дисциплине "Опе- рационные среды АСОИУ" / Сост.: В.В Сидельников, В.В. Широков; ГЭТУ. СПб., 1996. 64 с. ISBN Приведены общие сведения и рекомендации по выполнению лабо- раторных работ по дисциплине "Операционные среды АСОИУ". Предназначено для студентов специальности 220200 "Автомати- зированные системы обработки информации и управления". УТВЕРЖДЕНО редакционно-издательским советом университета в качестве методических указаний ББК 3 986 С С.-Пб. ГЭТУ, 1996 ISBN - 3 - Лабораторная работа 1 ИЗУЧЕНИЕ АЛГОРИТМОВ РЕАЛИЗАЦИИ И ИСПОЛЬЗОВАНИЯ СОПРОГРАММ Цель работы: ознакомление с алгоритмами реализации сопрог- рамм и способами их использования для организации многозадачности Общие сведения Сопрограммы - это средство прередачи управления из одной процедуры в другую без отношения вложенности. Выполняемой проце- дуре нет необходимости возвращаться в вызвавшую ее процедуру. Традиционные операторы ВЫЗОВ и ВОЗВРАТ в случае сопрограмм заме- няются одним оператором - ПЕРЕДАТЬ_УПРАВЛЕНИЕ. Сопрограммы обла- дают следующими свойствами: 1) позволяют имитировать параллельность с помощью явных пе- редач управления; 2) являются средством реализации многозадачного режима. Реализация сопрограмм основана на выделении собственного стека для каждой из процедур. Тогда оператор ПЕРЕДАТЬ_УПРАВЛЕНИЕ по существу выполняет операцию замены стека приостанавливаемой сопрограммы на стек возобновляемой сопрограммы. Работа процедур в качестве сопрограмм требует предваритель- ной подготовки, состоящей в выделении стека каждой из процедур и записи в стек точки входа в процедуру. Текущее состояние стека каждой из сопрограмм хранится в структуре, называемой ДЕСКРИП- ТОР_СОПРОГРАММЫ. Поэтому сопрограммы представляются своими деск- рипторами. Технология реализации и работы сопрограмм Поскольку работа со стеком требует доступа непосредственно к регистрам SS и SP, оператор ПЕРЕДАТЬ_УПРАВЛЕНИЕ может быть реали- зован только средствами языка АССЕМБЛЕРА. Оформление ассемблерной процедуры в среде Pascal: Procedure Name_Proc(Параметры-значения; Параметры-переменные); Assembler; {обязательный атрибут} Asm {обязательный атрибут} ... End; - 4 - Запись в адресуемую ячейку памяти производится оператором MemW[Seg:Ofs] := ... . Технология реализации сопрограмм представлена в форме описа- ния последовательностей действий производимых при создании соп- рограммы и при передаче управления от одной сопрограммы к другой. Procedure СОЗДАТЬ_СОПРОГРАММУ; Begin ВЫДЕЛИТЬ ПАМЯТЬ ПОД СТЕК; ВЫДЕЛИТЬ ПАМЯТЬ ПОД ДЕСКРИПТОР; ВЫЧИСЛИТЬ АДРЕС "ДНА" СТЕКА И ЗАПИСАТЬ ЕГО В ДЕСКРИПТОР; ПО АДРЕСУ "ДНА" СТЕКА ЗАПИСАТЬ ТОЧКУ ВХОДА В ПРОЦЕДУРУ; End; Procedure ПЕРЕДАТЬ_УПРАВЛЕНИЕ; Assembler; Asm СЧИТАТЬ АДРЕС ДЕСКРИПТОРА ПРИОСТАНАВЛИВАЕМОЙ СОПРОГРАММЫ; ЗАПИСАТЬ В ЭТОТ ДЕСКРИПТОР СОСТОЯНИЕ СТЕКА; СЧИТАТЬ АДРЕС ДЕСКРИПТОРА ВОЗОБНОВЛЯЕМОЙ СОПРОГРАММЫ; ВОССТАНОВИТЬ СОСТОЯНИЕ СТЕКА ИЗ ЭТОГО ДЕСКРИПТОРА; End; Технология работы сопрограмм представлена в форме "заготов- ки" программы: Program Cor; Procedure СОЗДАТЬ_СОПРОГРАММУ; Begin ... End; Procedure ПЕРЕДАТЬ_УПРАВЛЕНИЕ; Assembler; Asm ... End; Procedure User_1; Begin while true do begin ... ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в другую сопрограмму} - 5 - end; End; ... Procedure User_N; Begin while true do begin ... if УСЛОВИЕ then {завершение выполнения} ПЕРЕДАТЬ_УПРАВЛЕНИЕ {в главную программу} else ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в другую сопрограмму} end; End; Begin СОЗДАТЬ_СОПРОГРАММУ; {User_1} ... СОЗДАТЬ_СОПРОГРАММУ; {User_N} ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в одну из сопрограмм} End. Задание 1. Реализовать процедуры СОЗДАТЬ_СОПРОГРАММУ и ПЕРЕДАТЬ_УП- РАВЛЕНИЕ по их спецификациям, представленным выше. 2. Реализовать программу Cor, заменив словесные описания действий операторами языка Pascal. 3. Нарисовать состояния стека сопрограммы при создании, при- остановке и возобновлении. 4. В разрабатываемой демонстрационной программе организовать динамическое выделение и освобождение памяти под дескрипторы и стеки сопрограмм. 5. Реализовать сопрограммы, представив их в виде объектов, включающих следующие данные данные - адрес стека и значения ре- гистров SS и SP, а также следующие методы - создания, уничтожения и передачи управления. Отчет должен содержать тексты программ с комментариями и ри- сунки, отражающие состояния стеков сопрограмм. - 6 - Лабораторная работа 2 ИССЛЕДОВАНИЕ ПРИНЦИПОВ ДИСПЕТЧЕРИЗАЦИИ ПРОЦЕССОВ Цель работы: ознакомление с принципами реализации алгоритмов диспетчеризации процессов в многозадачных средах Общие сведения Реализация псевдопараллельного режима с помощью явного вклю- чения в пользовательские процессы оператора ПЕРЕДАТЬ_УПРАВЛЕНИЕ обладает недостатками: 1) Пользовательские процессы включают в себя действия, кото- рые по существу не относятся к их функциям; 2) Интервалы процессорного времени, предоставляемые процес- сам, зависят от самих процессов и есть опасность захвата процес- сора на длительный срок одним процессом. Поэтому в многозадачных системах используется принудительная передача управления. Моменты принудительной передачи управления определяются прерываниями от таймера. Такой способ передачи уп- равления называется диспетчеризацией. Работает многозадачная система с принудительной диспетчери- зацией следующим образом. Выполнение текущей сопрограммы приостанавливается прерывани- ем от таймера. Управление передается программе-обработчику преры- вания. Обработчик выполняет действия по выбору следующей сопрог- раммы и передает управление ей оператором ПЕРЕДАТЬ_УПРАВЛЕНИЕ. Таким образом каждой сопрограмме выделяется квант времени для выполнения. Сведения из языка Паскаль, используемые при реализации диспетчеризации Установка вектора прерывания: SetIntVec(IntNo : byte; Vector : pointer) где: IntNo - номер вектора прерывания; Vector - адрес процедуры-обработчика прерывания. Чтение вектора прерывания: GetIntVec(IntNo : byte; Var Vector : pointer) где: IntNo - номер вектора прерывания; - 7 - Vector - переменная, в которую пишется адрес процедуры-обра- ботчика прерывания. Примечание. Номер вектора прерывания от таймера - 8; номера свободных векторов для переустановки системного обработчика пре- рываний от таймера: 60-66; 78-7F. Структура процедуры-обработчика прерывания: Procedure Handler; interrupt; {обязательный атрибут} Begin ... End {Handler}. Технология реализации диспетчеризации Технология реализации диспетчеризации в среде Паскаль предс- тавлена "заготовкой" программы: Program User_Disp; Procedure ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; Assembler; Asm ... End; Procedure СОЗДАТЬ_СОПРОГРАММУ; Begin {Описана ранее} End; Procedure ПЕРЕДАТЬ_УПРАВЛЕНИЕ; Assembler; Asm {Описана ранее} End; Procedure Handler; interrupt; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; {Выбрать следующую сопрограмму} ПЕРЕДАТЬ_УПРАВЛЕНИЕ; End; Procedure User_1; Begin while true do begin - 8 - ... end; End; Procedure User_2; Begin while true do begin ... if УСЛОВИЕ then begin {завершение выполнения} ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ВОССТАНОВИТЬ_ВЕКТОР_ПРЕРЫВАНИЯ_ОТ_ТАЙМЕРА; ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в главную программу} end; end; End; Begin СОЗДАТЬ_СОПРОГРАММУ; {User_1} СОЗДАТЬ_СОПРОГРАММУ; {User_2} ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ПЕРЕУСТАНОВИТЬ_ВЕКТОР_ПРЕРЫВАНИЯ_ОТ_ТАЙМЕРА; УСТАНОВИТЬ_НА_ВЕКТОР_8_ПРОЦЕДУРУ_Handler; ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в User_i} End. Задание 1. Реализовать программу, раскрыв все предложения оператора- ми языка Паскаль. 2. Нарисовать состояния стека произвольной сопрограммы при приостановке ее прерыванием от таймера и возобновлении из обра- ботчика прерываний. 3. Отчет должен содержать текст программы, а также рисунки, отражающие состояния стека сопрограмм при прерываниях. - 9 - Лабораторная работа 3 ИССЛЕДОВАНИЕ ПРИНЦИПОВ РЕАЛИЗАЦИИ ПРОЦЕССОВ И ОЧЕРЕДЕЙ МНОГОЗАДАЧНОГО ЯДРА Цель работы: ознакомление с принципами реализации процессов и очередей в ядре многозадачной среды Общие сведения Параллельно выполняемые в многозадачной среде процедуры на- зываются процессами. Поскольку процессор один, а процессов много, то появляется средство упорядочивания доступа процессов к процессору, принимаю- щее форму очереди. Важнейшим видом очереди является очередь процессов, готовых к выполнению. Для обеспечения возможности включения процесса в очереди не- обходимо модифицировать дескриптор сопрограммы, реализующей про- цесс, введя в него поле - указатель на следующего. С учетом возможности динамического создания и уничтожения представим процесс как объект следующего вида: ПРОЦЕСС = ОБЪЕКТ {ДАННЫЕ:} ЭЛЕМЕНТЫ ДЕСКРИПТОРА СОПРОГРАММЫ; СЛЕДУЮЩИЙ; АДРЕС_СТЕКА; {МЕТОДЫ:} Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure УСТАНОВИТЬ_СЛЕДУЮЩИЙ; Function ПОЛУЧИТЬ_СЛЕДУЮЩИЙ; КОНЕЦ; Вторым видом объектов многозадачной среды является ОЧЕРЕДЬ, представляемая следующим описанием: ОЧЕРЕДЬ = ОБЪЕКТ {ДАННЫЕ:} НАЧАЛО; {МЕТОДЫ:} Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure ВКЛЮЧИТЬ_ПРОЦЕСС; Procedure ИСКЛЮЧИТЬ_ПРОЦЕСС; - 10 - Function ПОЛУЧИТЬ_НАЧАЛО; КОНЕЦ; В данной работе рассматривается очередь готовых процессов, которая может быть представлена как тип, производный от типа ОЧЕ- РЕДЬ: ОЧЕРЕДЬ_ГОТОВЫХ = ОБЪЕКТ(ОЧЕРЕДЬ) {МЕТОДЫ:} Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure ЗАПУСТИТЬ_ДИСПЕТЧЕР; Procedure ОСТАНОВИТЬ_ДИСПЕТЧЕР; Procedure ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС; Procedure АКТИВИЗИРОВАТЬ_СЛЕДУЮЩИЙ; КОНЕЦ; Технология реализации процессов и очереди готовых процессов Технология реализации процессов и очереди готовых процессов представлена в виде словесного описания библиотечного модуля, яв- ляющегося дальнейшим развитием программы лабораторной работы 2. Unit DispObj; Interface Type ПРОЦЕСС = ОБЪЕКТ ЭЛЕМЕНТЫ ДЕСКРИПТОРА СОПРОГРАММЫ; СЛЕДУЮЩИЙ; АДРЕС_СТЕКА; Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure УСТАНОВИТЬ_СЛЕДУЮЩИЙ; Function ПОЛУЧИТЬ_СЛЕДУЮЩИЙ; КОНЕЦ; ОЧЕРЕДЬ = ОБЪЕКТ НАЧАЛО; Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure ВКЛЮЧИТЬ_ПРОЦЕСС; Procedure ИСКЛЮЧИТЬ_ПРОЦЕСС; Function ПОЛУЧИТЬ_НАЧАЛО; - 11 - КОНЕЦ; ОЧЕРЕДЬ_ГОТОВЫХ = ОБЪЕКТ(ОЧЕРЕДЬ) Procedure ИНИЦИАЛИЗИРОВАТЬ; Procedure ОСВОБОДИТЬ_ПАМЯТЬ; Procedure ЗАПУСТИТЬ_ДИСПЕТЧЕР; Procedure ОСТАНОВИТЬ_ДИСПЕТЧЕР; Procedure ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС; Procedure АКТИВИЗИРОВАТЬ_СЛЕДУЮЩИЙ; КОНЕЦ; Var ReadyList : ОЧЕРЕДЬ_ГОТОВЫХ; Implementation Procedure ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; Assembler; Asm ... End; Procedure РАЗРЕШИТЬ_ПРЕРЫВАНИЯ; Assembler; Asm ... End; Procedure СОЗДАТЬ_СОПРОГРАММУ; Begin ... End; Procedure ПЕРЕДАТЬ_УПРАВЛЕНИЕ; Assembler; Asm ... End; Procedure Handler; interrupt; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ReadyList.АКТИВИЗИРОВАТЬ_СЛЕДУЮЩИЙ; End; Procedure Idler; {всегда в очереди готовых} Begin while true do begin end; End; Procedure ПРОЦЕСС.ИНИЦИАЛИЗИРОВАТЬ; - 12 - Begin СОЗДАТЬ_СОПРОГРАММУ; ЗАПОЛНИТЬ ПОЛЕ АДРЕС_СТЕКА; End; Procedure ПРОЦЕСС.ОСВОБОДИТЬ_ПАМЯТЬ; Begin ОСВОДИТЬ ПАМЯТЬ, ЗАНЯТУЮ ПОД СТЕК; End; Procedure ПРОЦЕСС.УСТАНОВИТЬ_СЛЕДУЮЩИЙ; Begin СЛЕДУЮЩИЙ := ... ; End; Function ПРОЦЕСС.ПОЛУЧИТЬ_СЛЕДУЮЩИЙ; Begin ПОЛУЧИТЬ_СЛЕДУЮЩИЙ := СЛЕДУЮЩИЙ; End; Procedure ОЧЕРЕДЬ.ИНИЦИАЛИЗИРОВАТЬ; Begin НАЧАЛО := NIL; End; Procedure ОЧЕРЕДЬ.ОСВОБОДИТЬ_ПАМЯТЬ; Begin {Цикл по всем процессам очереди} ПРОЦЕСС.ОСВОБОДИТЬ_ПАМЯТЬ; End; Procedure ОЧЕРЕДЬ.ВКЛЮЧИТЬ_ПРОЦЕСС; Begin ... End; Procedure ОЧЕРЕДЬ.ИСКЛЮЧИТЬ_ПРОЦЕСС; Begin ... End; Function ОЧЕРЕДЬ.ПОЛУЧИТЬ_НАЧАЛО; Begin ПОЛУЧИТЬ_НАЧАЛО := НАЧАЛО; End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.ИНИЦИАЛИЗИРОВАТЬ; Begin - 13 - ОЧЕРЕДЬ.ИНИЦИАЛИЗИРОВАТЬ; End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.ОСВОБОДИТЬ_ПАМЯТЬ; Begin ОЧЕРЕДЬ.ОСВОБОДИТЬ_ПАМЯТЬ; End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.ЗАПУСТИТЬ_ДИСПЕТЧЕР; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ПЕРЕУСТАНОВИТЬ_ВЕКТОР_ПРЕРЫВАНИЯ_ОТ_ТАЙМЕРА; УСТАНОВИТЬ_НА_ВЕКТОР_8_ПРОЦЕДУРУ_Handler; ПОЛУЧИТЬ_НАЧАЛО; ИСКЛЮЧИТЬ_ПРОЦЕСС; ПЕРЕДАТЬ_УПРАВЛЕНИЕ; End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.ОСТАНОВИТЬ_ДИСПЕТЧЕР; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ВОССТАНОВИТЬ_ВЕКТОР_ПРЕРЫВАНИЯ_ОТ_ТАЙМЕРА; ПЕРЕДАТЬ_УПРАВЛЕНИЕ; {в главную программу} End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ПРОЦЕСС.ИНИЦИАЛИЗИРОВАТЬ; ВКЛЮЧИТЬ_ПРОЦЕСС; РАЗРЕШИТЬ_ПРЕРЫВАНИЯ; End; Procedure ОЧЕРЕДЬ_ГОТОВЫХ.АКТИВИЗИРОВАТЬ_СЛЕДУЮЩИЙ; Begin ЗАПРЕТИТЬ_ПРЕРЫВАНИЯ; ВКЛЮЧИТЬ_ПРОЦЕСС; {текущий} ПОЛУЧИТЬ_НАЧАЛО; ИСКЛЮЧИТЬ_ПРОЦЕСС; ПЕРЕДАТЬ_УПРАВЛЕНИЕ; End; Begin ReadyList.ИНИЦИАЛИЗИРОВАТЬ; ReadyList.ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС;{Включение Idler} - 14 - End. С учетом приведенного библиотечного модуля пользовательская программа выглядит следующим образом: Program User; Uses Disp; Procedure User_1; Begin while true do begin ... end; End; Procedure User_N; Begin while true do begin ... if УСЛОВИЕ then then begin {завершение выполнения} ReadyList.ОСТАНОВИТЬ_ДИСПЕТЧЕР; end; end; End; Begin ReadyList.ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС;{Включение User_1} ReadyList.ДОБАВИТЬ_НОВЫЙ_ПРОЦЕСС;{Включение User_N} ReadyList.ЗАПУСТИТЬ_ДИСПЕТЧЕР; End. Задание 1. В соответствии с приведенными выше заготовками реализо- вать библиотечный модуль, обеспечивающий работу с очередью гото- вых процессов, учитывая динамическое выделение памяти под процес- сы. 2. Составить пример, иллюстрирующий работу библиотечного мо- дуля. 3. Отчет должен содержать тексты программ библиотечного мо- дуля и примера. - 15 - Лабораторная работа 4 ИССЛЕДОВАНИЕ СИСТЕМНЫХ ОЧЕРЕДЕЙ МНОГОЗАДАЧНОГО ЯДРА Цель работы: изучение системных очередей многозадачного ядра Общие сведения Самой важной системной очередью ядра является очередь гото- вых процессов, рассмотренная в лабораторной работе 3. В данной работе рассмотрим другие очереди ядра, которые принято относить к системным. Очередь задержанных процессов Эта очередь даже проще очереди готовых и представлена для полноты описания. Дело в том, что все невыполняющиеся процессы должны находиться в каких-либо очередях. Поэтому если программной системе необходимо приостановить выполнение некоторого процесса, то этот процесс должен быть помещен в специально выделенную оче- редь, которую назовем очередью задержанных, где он будет нахо- диться до тех пор пока системе не понадобится его возобновление. В этом случае процесс извлекается из очереди задержанных и поме- щается в очередь готовых процессов. Описание такой очереди может выглядеть следующим образом: Type List = Object First : Process; Constructor Init; Destructor Done; Virtual; Procedure Insert(P : Process); Procedure Remove(P : Process); End {List}. Очередь процессов, задержанных на время Данный объект выполняет функции классической временной за- держки выполнения программы, например, Delay(T : Word), которая обеспечивает "активное" ожидание, допустимое в однозадачной сре- де. В многозадачной среде при необходимости задержать на время - 16 - процесс его целесообразно снять из очереди готовых и тем самым распределять процессорное время уже между меньшим числом процес- сов. Технология реализации очереди, выполняющей функции задержки процессов на время, основана на следующих положениях: 1. Мультизадачная среда "знает" текущее время, которое может подсчитываться количеством вызовов диспетчера-обработчика преры- ваний от таймера. 2. В момент обращения процесса к методу "задержать на время Т" процесс переводится в очередь, а в специальное поле дескрипто- ра процесса пишется время его активизации, равное сумме текущего времени и интервала Т задержки. 3. Диспетчер на каждом прерывании проверяет очередь задер- жанных на наличие процессов, для которых совпало текущее время с временем их активизации и переводит эти процессы в очередь гото- вых. С учетом приведенных положений описание очереди задержанных будет выглятеть следующим образом: Type DelayList = Object(List) Procedure Delay(T : Word); Procedure Activisation; End {DelayList}. Метод DelayList.Activisation помещается в диспетчер. Дадим словесное описание метода DelayList.Delay(T : Word). Procedure DelayList.Delay(T : Word); Var Предыдущий : Процесс; Begin Предыдущий := Текущий; Предыдущий^.Tact := T + Tcur; Включить(Предыдущий); Текущий := Очередь_Готовых.Первый; Очередь_Готовых.Извлечь(Текущий); Передать_Управление(Предыдущий, Текущий); End {DelayList.Delay}. Дадим словесное описание метода DelayList.Activisation: Procedure DelayList.Activisation; - 17 - Var Текущий, Следующий : Процесс; Begin Текущий := Первый; Пока Текущий <> NIL Делать Начало Следующий := Текущий^.Следующий; Если Текущий^.Tact = Tcur То Начало Извлечь(Текущий); Очередь_Готовых.Включить(Текущий); Конец {Если}; Текущий := Следующий; Конец {Пока}; End {DelayList.Activisation}. Очередь уничтожаемых процессов Чтобы уничтожить процесс, находящийся в какой-либо очереди, необходимо изъять процесс из этой очереди и разрушить его деск- риптор. В таком уничтожении процесса проблем нет. Проблемы возни- кают, когда требуется уничтожить активный процесс, т.е. выполняю- щийся в текущий момент времени. Например, процесс закончил выпол- нять предписанные ему действия и желает самоуничтожиться. В этом случае просто разрушить дескриптор процесса нельзя, т.к. передача управления осуществляется от активного процесса первому в очереди готовых процессов через их дескрипторы, поэтому если дескриптор активного процесса разрушить, то функции Transfer(Old, New : Pro- cess) будет передан указатель на несуществующий дескриптор и сис- тема зависнет. Поэтому технология корректного уничтожения процесса состоит в следующем: 1. Процесс, желающий самоуничтожиться, переводится в специ- альную очередь уничтожаемых процессов. При этом дескриптор про- цесса на данном этапе не разрушается. 2. Диспетчер на каждом прерывании очищает очередь уничтожае- мых процессов, разрушая дескрипторы всех процессов, находящихся в очереди. С учетом приведенных положений описание очереди уничтожаемых процессов выглядит следующим образом: Type - 18 - KillList = Object(List) Procedure SelfInsert; Procedure Clear; End {KillList}. Метод KillList.Clear помещается в диспетчер и вызывается на каждом прерывании от таймера. Дадим словесное описание метода KillList.Clear. Procedure KillList.Clear; Var Временный : Процесс; Begin Пока Первый <> NIL Делать Начало Временный := Первый; Первый := Временный^.Следующий; Разрушить(Временный); Конец {Пока}; End {KillList.Clear}. Примитив ядра УНИЧТОЖИТЬ_ПРОЦЕСС(P : ПРОЦЕСС) выглядит сле- дующим образом KillList.Insert(P). При самоуничтожении процесс должен обратиться к методу: KillList.SelfInsert. Заметим, что процесс никогда не должен заканчиваться выходом на End процедуры, которая его описывает, а только вызовом Kill- List.SelfInsert. Задание 1. Используя материалы предыдущих лабораторных работ и представленное выше описание системных очередей, реализовать объ- екты: очередь задержанных процессов, очередь процессов, задержан- ных на время, очередь уничтожаемых процессов. 2. Перечисленные объекты добавить в библиотечный модуль, ре- ализующий ядро. 3. Реализовать программу, демонстрирующую работоспособность разработанных объектов. - 19 - Лабораторная работа 5 ИССЛЕДОВАНИЕ МЕТОДОВ СИНХРОНИЗАЦИИ ПРОЦЕССОВ Цель работы: знакомство с методами синхронизации процессов на основе семафоров Общие сведения Синхронизацией называется обеспечение заданной очередности прохождения процессов через определенные состояния. Наиболее часто синхронизация требуется для координации дос- тупа нескольких процессов к одному разделяемому ресурсу. Рассмотрим простейший пример. Предположим, что два процесса выводят информацию в виде символа в разные точки экрана. Фрагмент текста процедур, соответствующих процессам, выгля- дит следующим образом: Процесс 1 Процесс 2 (1) GoTo(X,Y); (3) GoTo(X,Y); (2) Write(Ch); (4) Write(Ch); При выполнении процессов в режиме разделения времени возмож- на следующая ситуация, когда оператором GoTo(X,Y) курсор устанав- ливается в нужную точку экрана одним процессом, затем под дейс- твием диспетчера происходит передача управления другому процессу, который в это время выполняет оператор вывода символа. То есть очередность выполнения действий такова: 1, 3, 2, 4 или 3, 1, 4, 2. Очевидно, что в этом случае один из процессов выведет информа- цию не в то место экрана, куда планировал. Суть исправления ошибки состоит в обеспечении неделимости выполнения последовательности действий GoTo(X,Y) и Write(Ch). В более общем смысле ситуация представляется следующим обра- зом. Экран в данном случае выступает в роли разделяемого ресурса, который два процесса используют совместно и одновременно. Ошибка возникает при отсутствие регламентации доступа к разделяемому ре- сурсу, а регламентация доступа заключается в том, что если один процесс работает с общим ресурсом, то другой процесс не должен в это же время работать с ним. - 20 - Используемый совместно несколькими процессами ресурс называ- ется критическим, участок программы процесса, реализующий работу с критическим ресурсом, называется критическим участком, а режим, при котором только один процесс в произвольный момент времени мо- жет работать с критическим ресурсом (или находиться в критическом участке), называется режимом взаимного исключения. В системах реального времени пренебрежение регламентацией доступа нескольких процессов к критическому ресурсу может приво- дить к катастрофическим последствиям. Методы обеспечения режима взаимного исключения Можно выделить три принципиальных пути обеспечения режима взаимного исключения. 1) Запрет прерываний на входе в критический участок и разре- шение прерываний на выходе из него. То есть фрагмент программы работы с критическим участком выглядит следующим образом: Запрет прерываний: Критический участок; Разрешение прерываний. Первым и единственным войдет в свой критический участок вой- дет тот процесс, который первым доберется до инструкции CLI в функции Запрет прерываний. Прерывания будут запрещены, диспетчер прекратит работу и все другие процессы естественным образом будут приостановлены. После выхода из критического участка прерывания будут разрешены и какой-то другой процесс сможет войти в свой критический участок. Такой способ организации взаимного исключения обладает су- щественными недостатками: - при запрете прерываний система становится слепой и глухой к внешним воздействиям окружающей среды, которые формируются, как правило, через систему прерываний; - приостанавливаются даже те процессы, которые вообще не ра- ботают с данным ресурсом. Поэтому данный способ организации взаимного исключения при- меняется в тех случаях, когда критический участок очень короткий, - 21 - например, несколько инструкций. 2) Активное ожидание. В этом случае вводится некоторый флаг занятости ресурса, ко- торый проверяется процессом перед тем, как войти в критический участок. Если флаг, который в начале устанавливается в состояние СВОБОДЕН, находится в состоянии СВОБОДЕН, то процесс переводит флаг в состояние ЗАНЯТ, и входит в критический участок. При выхо- де из критического участка процесс устанавливает флаг в состояние СВОБОДЕН. Если при подходе к критическому участку флаг оказывает- ся в состоянии ЗАНЯТ, то процесс начинает проверять состояние флага в цикле до тех пор пока флаг не будет установлен в состоя- ние СВОБОДЕН другим процессом. То есть фрагменты процедуры. описывающие процесс на этапах входа в критический участок и выхода из него, выглядят следующим образом: Инициализация: FLAG := СВОБОДЕН; While FLAG = ЗАНЯТ Do Begin End {While}; FLAG := ЗАНЯТ; Критический участок; FLAG := СВОБОДЕН; В данном случае сам флаг является критическим ресурсом и доступ к нему должен производиться в режиме взаимного исключения. Фрагмент входа в критический участок с проверкой и установкой флага в режиме взаимного исключения выглядит следующим образом (состояние ЗАНЯТ соответствует FLAG = 1): LBL : STI CLI CMP FLAG, 1 JZ LBL MOV FLAG, 1 STI Если чтение и установку флага выполнять за одну инструкцию, которая является неделимым действием, то вход в критический учас- ток можно выполнить более элегантно, а именно, MOV AX, 1 - 22 - LBL : XCHG AX, FLAG CMP AX, 1 JZ LBL Недостатком приведенного метода реализации взаимного исклю- чения является активное ожидание, то есть процесс, который ждет освобождения ресурса, занимает процессор в отводимые ему диспет- чером кванты времени, хотя и не выполняет никаких полезных дейс- твий. Поэтому в случае необходимости ожидания освобождения ресурса целесообразно снять процесс из очереди готовых процессов и не предоставлять ему бесполезно используемых квантов времени. На этом положении основано использование семафоров как средств вза- имного исключения при доступе к критическому ресурсу. 3) Семафоры. Семафор представляет собой объект, включающий счетчик и оче- редь. В очередь помещаются процессы, ждущие наступления некоторо- го события, например, освобождения ресурса. Условия помещения процесса в очередь и извлечения из очереди с целью активизации определяются состоянием счетчика и проверяются двумя операциями над семафором, которые называются P и V операции. Принципы работы с семафором можно описать следующим образом. В исходном состоянии семафор открыт. Процесс проходит через отк- рытый семафор в критический участок и закрывает за собой семафор. Другой процесс, подходя к критическому участку, натыкается на закрытый семафор и вынужден ждать его открытия в очереди семафо- ра. Процесс, выходя из критического участка, открывает семафор и активизирует первый в очереди семафора процесс, так что теперь этот процесс может войти в критический участок и также закрыть за собой семафор. Состояние счетчика семафора играет роль индикатора занятости ресурса. Принято инициализировать счетчик в 1, декрементировать при подходе к критическому участку (Р - операция) и инкрементиро- вать при выходе из критического участка (V - операция). Таким об- разом равенство нулю счетчика свидетельствует о возможности входа в критический участок, а отрицательное значение счетчика свиде- тельствует о наличии процесса в критическом участке и необходи- мости блокировки, то есть переводе в очередь семафора с передачей - 23 - управления другим процессам. Технология реализации семафора Технология реализации семафора представлена в виде описания семафора как объекта языка программирования. Type PSemaphore = ^TSemaphore; TSemaphore = Object Счетчик : Целое; Очередь_семафора : Очередь процессов; Constructor Init(С : Целое); Destructor Done; Virtual; Procedure P; Procedure V; End {TSemaphore}. Constructor TSemaphore.Init(Целое); Begin Счетчик := С; Создать Очередь_семафора; End {TSemaphore.Init}; Destructor TSemphore.Done; Begin Разрушить Очередь_семафора; End {TSemaphore.Done}; Procedure TSemaphore.P; Var Предыдущий : Процесс; Begin Запретить_прерывания; Счетчик := Счетчик - 1; If Счетчик < 0 Then Begin {блокировать процесс} Предыдущий := Текущий; Очередь_семафора.Включить(Предыдущий); Текущий := Очерередь_готовых.Первый; Очередь_готовых.Извлечь(Текущий); Передать_управление(Предыдущий, Текущий); End {If}; Разрешить_прерывания; - 24 - End {TSemaphore.P}; Procedure TSemaphore.V; Var Предыдущий : Процесс; Begin Запретить_прерывания; Счетчик := Счетчик + 1; If Счетчик <= 0 Then Begin {активизировать процесс} Предыдущий := Текущий; Очередь_готовых.Включить(Предыдущий); Текущий := Очередь_семафора.Первый; Очередь_семафора.Извлечь(Текущий); Передать_управление(Предыдущий, Текущий); End {If}; Разрешить_прерывания; End {TSemaphore.V}. Здесь процесс, вызвавший метод TSemaphore.V, переводится в очередь готовых и активизирует процесс, стоящий первым в очереди семафора. Технология использования семафоров В первую очередь семафоры используются как средства взаимно- го исключения при доступе к критическому ресурсу. Правило исполь- зования семафора в этом случае представлено в виде фрагмента про- цедуры, описывающей процесс при входе в критический участок и вы- ходе из него. Раздел описания: Var Semaphore : TSemaphore; Раздел инициализации: Semaphore.Init(1); Процесс при работе с критическим участком: Semaphore.P; Критический участок; Semaphore.V; - 25 - Завершение работы с семафором: Semaphore.Done; Семафоры могут быть использованы не только для координации доступа к критическому ресурсу нескольких процессов, но и для ус- тановления требуемой очередности прохождения процессами опреде- ленных состояний. Пусть, например, необходимо, чтобы процесс Р1 прошел через состояние, отмеченное меткой М_Р1, например, чтение из ячейки памяти П, только после того, как процесс Р2 пройдет че- рез состояние, отмеченное меткой М_Р2, например, запись в ячейку памяти П. То есть запись должна произойти раньше чтения. С помощью семафора данная задача решается следующим образом: Инициализация семафора: Semaphore.Init(0); Процесс Р1 Процесс Р2 Semaphore.P; М_Р1 : Чтение из П; М_Р2 : Запись в П; Semaphore.V; Если процесс Р1 подойдет к метке М_Р1 раньше, чем процесс Р2 подойдет к метке М_Р2, то он будет вынужден блокироваться в очереди семафора. Процесс Р2, выполнив запись в ячейку П, вызовет Semaphore.V и тем самым активизирует процесс Р1, позволив ему вы- полнить чтение только после того как осуществлена запись. Часто процессы реализуются в виде бесконечных циклов, поэто- му чтобы не произошло нескольких записей в ячейку П одним процес- сом до того как произойдет чтение из ячейки П другим процессом, необходимо последующие записи осуществлять только после очередно- го чтения. Указанная схема реализуется следующим образом: Инициализация семафора: Semaphore1.Init(0); Инициализация семафора: Semaphore2.Init(0); Процесс Р1 Процесс Р2 While True Do Begin While True Do Begin . . . . . . - 26 - Semaphore1.P; М_Р1 : Чтение из П; М_Р2 : Запись в П; Semaphore2.V; Semaphore1.V; Semaphore2.P; . . . . . . End {While}; End {While}. Теперь процесс Р2, выполнив запись, и сигнализировав об этом вызовом Semaphore1.V, ожидает, приостановленный вызовом Semapho- re2.P, чтения процессом Р1, о чем Р1 будет сигнализировать вызо- вом Semaphore2.V. В этой схеме методы семафора Semaphore2 выпол- няют роль ожидания и посылки квитанции, подтверждающей чтение. Задание 1. Реализовать объект - семафор, используя средства, разра- ботанные при выполнении лабораторных работ 1 - 4. 2. Написать демонстрационную программу, иллюстрирующую коор- динацию доступа к критическому ресурсу с помощью реализованного семафора. 3. Написать демонстрационную программу, иллюстрирующую синх- ронизацию прохождения процессов через определенные состояния с помощью реализованного объекта - семафор. 4. Отчет должен содержать текст библиотечного модуля, вклю- чающего описание и реализацию объекта - семафор, тексты демонс- трационных программ с комментариями, таблицы состояний счетчиков семафоров при различных вариантах очередности прохождения процес- сов (для числа процессов, большего, чем 2) через вызовы P и V ис- пользуемых семафоров. - 27 - Лабораторная работа 6 ИССЛЕДОВАНИЕ МЕТОДОВ БУФЕРИЗАЦИИ СООБЩЕНИЙ Цель работы: изучение метода обмена сообщениями между про- цессами с помощью буфера Общие сведения Буферизация является средством согласования скорости записи сообщений одним процессом и скорости чтения сообщений другим про- цессом. При этом буфер является общим, разделяемым объектом для пишущего и читающего процессов. Существуют следующие требования к алгоритмам функционирова- ния буфера: 1) нельзя записать сообщение в полный буфер; процесс, делаю- щий такую попытку, должен быть блокирован до появления свободной ячейки в буфере; 2) нельзу прочитать сообщение из пустого буфера; процесс, делающий такую попытку, должен быть блокирован до появления сооб- щения в буфере. Как правило, механизмы синхронизации записи в буфер и чтения из буфера являются скрытыми для пользователя, которым предостав- ляются лишь примитивы СОЗДАТЬ, УНИЧТОЖИТЬ, ЗАПИСАТЬ и ПРОЧИТАТЬ, внешне напоминающие работу с файлами. Простейший вариант синхронизации записи и чтения для буфера размером в 1 ячейку памяти был рассмотрен в лабораторной работе 5. В данной работе рассматривается общий случай буфера размером в N элементов. Структура буфера Буфер представляет собой массив из N элементов определенного типа. Состояние буфера описывается количеством n сообщений, нахо- дящихся в буфере, и двумя индексами - индексом out чтения и ин- дексом in записи. Запись в буфер предваряется проверкой условия "буфер полон", то есть n = N, чтение из буфера предваряется проверкой условия "буфер пуст", то есть n = 0. Выполнение условия "буфер полон" означает, что скорость за- писи опередила скорость чтения, а выполнение условия "буфер пуст" - 28 - означает, что скорость чтения опередила скорость записи. В нор- мальном состоянии значение индекса записи немного превышает зна- чение индекса чтения, что иллюстрируется следующим рисунком: ┌──────────────────┐ │ │ ├──────────────────┤ │//////////////////│ ─────────> out чтение ├──────────────────┤ │//////////////////│ (следующее чтение) ├──────────────────┤ │//////////////////│ ├──────────────────┤ запись in ──────> │ │ ├──────────────────┤ (следующая запись) │ │ └──────────────────┘ Как правило, буфер рассматривается как кольцевой, то есть после записи в последнюю ячейку буфера запись продолжается с пер- вой ячейки буфера, чтение осуществляется аналогично. Синхронизация записи и чтения реализуется использованием очередей ожидания двух видов: - очереди процессов, ждущих записи, когда буфер полон; - очереди процессов, ждущих чтения, когда буфер пуст. Описание буфера Представим буфер в виде объекта: TBuffer = Object in, out : [0..N-1]; n : [0..N]; Buf : Array[0..N-1] Of AnyType; ReadList, WriteList : TList; Constructor Init; Destructor Done; Virtual; Procedure Write(M : AnyType); Procedure Read(Var M : AnyType); Procedure Wait_Read; Procedure Signal_Read; Procedure Wait_Write; - 29 - Procedure Signal_Write; End {TBuffer}. Constructor TBuffer.Init; Begin in := 0; out := 0; n := 0; ReadList.Init; WriteList.Init; End {TBuffer.Init}; Destructor TBuffer.Done; Begin ReadList.Done; WriteList.Done; End {TBuffer.Done}; Синхронизация записи и чтения реализуется следующими четырь- мя методами объекта - буфер. Procedure TBuffer.Wait_Read; {заставляет процесс ждать чтения, если буфер пустой} Var Предыдущий : Процесс; Begin Предыдущий := Текущий; ReadList.Включить(Предыдущий); Текущий := Очерередь_готовых.Первый; Очередь_готовых.Извлечь(Текущий); Передать_управление(Предыдущий, Текущий); End {TBuffer.Wait_Read}; Procedure TBuffer.Wait_Write; {заставляет процесс ждать записи, если буфер полный} Var Предыдущий : Процесс; Begin Предыдущий := Текущий; WriteList.Включить(Предыдущий); Текущий := Очерередь_готовых.Первый; Очередь_готовых.Извлечь(Текущий); Передать_управление(Предыдущий, Текущий); End {TBuffer.Wait_Write}; Procedure TBuffer.Signal_Read; - 30 - {"сигнализирует" о том, что произведена запись и возможна активи- зация одного из процессов, ждущих чтения} Var Локальный : Процесс; Begin Локальный := ReadList.Первый; If Локальный <> NIL Then Begin {очередь не пустая} ReadList.Извлечь(Локальный); Очередь_готовых.Включить(Локальный); End {If}; End {TBuffer.Signal_Read}. Procedure TBuffer.Signal_Write; {"сигнализирует" о том, что произведено чтение и возможна активи- зация одного из процессов, ждущих записи} Var Локальный : Процесс; Begin Локальный := WriteList.Первый; If Локальный <> NIL Then Begin {очередь не пустая} WriteList.Извлечь(Локальный); Очередь_готовых.Включить(Локальный); End {If}; End {TBuffer.Signal_Write}. Procedure TBuffer.Write(M : AnyType); Begin Запретить прерывания; If n = N Then Wait_Write; {буфер полный} n := n + 1; Buf[in] := M; in := (in + 1) MOD N; Signal_Read; Разрешить прерывания; End {TBuffer.Write}; Procedure TBuffer.Read(Var M : AnyType); Begin Запретить прерывания; If n = 0 Then Wait_Read; {буфер пустой} n := n - 1; М := Buf[out]; - 31 - out := (out + 1) MOD N; Signal_Write; Разрешить прерывания; End {TBuffer.Read}; В методах Signal_Read и Signal_Write управление не передает- ся активизируемым процессам, а они лишь ставятся в очередь гото- вых процессов. Это может породить неопределенность, состоящую в том что, пока до их выполнения дойдет очередь, неизвестно, что будет с буфером. Поэтому активизацию процессов лучше выполнять не до включения в очередь готовых процессов, а до передачи управле- ния активизируемому процессу. Метод Signal_Read для этого случая представлен ниже, а метод Signal_Write реализуется аналогично. Procedure TBuffer.Signal_Read; Var Предыдущий, Локальный : Процесс; Begin Локальный := ReadList.Первый; If Локальный <> NIL Then Begin {очередь не пустая} Предыдущий := Текущий; Текущий := Локальный; ReadList.Извлечь(Локальный); Очередь_готовых.Включить(Предыдущий); Передать_управление(Предыдущий, Текущий); End {If}; End {TBuffer.Signal_Read}. Задание 1. Реализовать объект - буфер в библиотечном модуле для не- которого типа передаваемых данных. 2. Написать демонстрационную программу, иллюстрирующую рабо- ту буфера при различных скоростях записи и чтения сообщений. Ско- рости записи и чтения можно менять путем изменения количества процессов, пишущих в буфер или читающих из буфера, или включая операторы задержки между следующими действиями: - порождением сообщения и записью его в буфер; - чтением сообщения из буфера и обработкой сообщения. - 32 - Лабораторная работа 7 ИССЛЕДОВАНИЕ МЕТОДА ВЗАИМОДЕЙСТВИЯ ПРОЦЕССОВ С ПОМОЩЬЮ ОЧЕРЕДЕЙ СООБЩЕНИЙ Цель работы: изучение методов взаимодействия процессов с по- мощью очередей сообщений Общие сведения Обмен сообщениями между процессами на основе буфера, расс- мотренный в лабораторной работе 6, обладает рядом недостатков, а именно, - ограничено (размером буфера) количество сообщений, помеща- емых в буфер; - сообщения переписываются в буфер и читаются из буфера, т.о. времена записи и чтения определяются типом (размером) сооб- щения и могут быть большими. Поэтому в ряде операционных сред, а именно, UNIX, OS/2 су- ществует другое средство обмена сообщениями, которое называется очередью сообщений. В действительности только очередью сообщений такое средство не ограничивается, а представляет собой целый объ- ект, включающий кроме очереди сообщений, еще и средства синхрони- зации записи и чтения. В качестве последних выступают очередь процессов, пославших сообщение, и очередь процессов, ждущих сообщение. Дадим словесное описание методов записи и чтения сообщения, а затем опишем данное средство обмена сообщениями как объект опе- рационной среды. Запись сообщения включает в себя следующие действия: - включение указателя на сообщения в очередь, (обратим вни- мание, что именно указатель помещается в очередь, а не само сооб- щение, что существенно повышает скорость обмена); - включение процесса, пославшего сообщения в очередь, тем самым процесс, пославший сообщение блокируется до момента чтения сообщения другим процессом; - активизация процесса, ждущего сообщения, если таковой име- ется. Чтение сообщения включает в себя следующие действия: - если сообщения отсутствуют, то блокировка процесса путем - 33 - постановки его в очередь; - если сообщение есть, то чтение сообщения и - активизация процесса, пославшего сообщение. Таким образом, процесс, пославший сообшение, возобновит свое выполнение только после того как его сообщение будет прочитано другим процессом. Схематично взаимодействие процессов для случаев, когда обра- щение одного процесса к примитиву записи сообщения происходит раньше обращения другого процесса к примитиву чтения, и наоборот, представлены на рисунках. Процесс 1 Процесс 2 ┌──────┴──────┐ │ │ запись │ │ └──────┬──────┘ │ │ожидание │ ┌──────┴──────┐ ┌───────┴───────┐ │возобновление│ │ чтение │ └──────┬──────┘----------------------└───────┬───────┘ Рис.1. Процесс 1 подошел к примитиву записи раньше, чем про- цесс 2 подошел к примитиву чтения. Процесс 2 Процесс 2 │ ┌──────┴──────┐ │ │начало чтения│ │ └──────┬──────┘ │ │ожидание ┌───────┴───────┐ ┌──────┴──────┐ │ запись │ │конец чтения│ └───────┬───────┘----------------------└──────┬──────┘ Рис.2. Процесс 1 подошел к примитиву записи позже, чем про- цесс 2 подошел к примитиву чтения. Средство обмена сообщениями, удовлетворяющее приведенному выше описанию, может быть предствлено следующим образом: ТPostBox = Object MessageList : TMessageList;{очередь указателей на сообщения} SendProcList : TList;{очередь процессов, пославших сообщения} WaitProcList : TList; {очередь процессов. ждущих сообщение} - 34 - Constructor Init; Destructor Done; Virtual; Procedure PutMsg(M : Pointer); {послать сообщение} Function GetMsg : Pointer; {принять сообщение} End {TPostBox}. Очередь указателей на сообщения по своим методам очень похо- жа на очередь процессов за исключением того, что оперирует с ти- пом данных Pointer, а не с типом данных Процесс. Constructor TPostBox.Init; Begin MessageList.Init; SendProcList.Init; WaitProcList.Init; End {TPostBox.Init}; Destructor TPostBox.Done; Begin MessageList.Done; SendProcList.Done; WaitProcList.Done; End {TPostBox.Done}; Procedure TPostBox.PutMsg(M : Pointer); Var Предыдущий : Процесс; Begin Запретить_прерывания; MessageList.Insert(M); Предыдущий := Текущий; SendProcList.Insert(Предыдущий); If WaitProcList.Первый <> NIL Then Begin Текущий := WaitProcList.Первый; WaitProcList.Remove(Текущий); End Else Begin Текущий := ReadyList.Первый; ReadyList.Remove(Текущий); End {If}; Передать_управление(Предыдущий, Текущий); Разрешить_прерывания; End {TPostBox.PutMsg}; - 35 - Function TPostBox.GetMsg : Pointer; Var M : Pointer; S : Процесс; Предыдущий : Процесс; Begin Запретить_прерывания; If MessageList.Первый = NIL Then Begin Предыдущий := Текущий; WaitProcList.Insert(Предыдущий); Текущий := ReadyList.Первый; ReadyList.Remove(Текущий); Передать_управление(Предыдущий, Текущий); Запретить_прерывания; End {If}; M := MessageList.Первый; MessageList.Remove(M); GetMsg := M; S := SendProcList.Первый; SendProcList.Remove(S); ReadyList.Insert(S); Разрешить_прерывания; End {TPostBox.GetMsg}. Представленный объект лишь моделирует в среде MS DOS работу очередей сообщений, реализованных в системах UNIX и OS/2, однако дает представление о путях решения задачи синхронизации записи и чтения сообщений разными процессами. С точки зрения синхронизации записи и чтения, состоящей в том что процессы возобновляют работу только после того как запись и чтение завершены, представленный объект похож на механизм Ран- деву языка реального времени Ада. Задание 1. Реализовать объект TPostBox средствами языка Pascal. 2. Прокомментировать каждую строчку объекта TPostBox. 3. Написать демонстрационную программу, иллюстрирующую функ- ционирование объекта TPostBox. - 36 - Содержание Лабораторная работа 1 "ИЗУЧЕНИЕ АЛГОРИТМОВ РЕАЛИЗАЦИИ И ИС- ПОЛЬЗОВАНИЯ СОПРОГРАММ".........................................3 Лабораторная работа 2 "ИССЛЕДОВАНИЕ ПРИНЦИПОВ ДИСПЕТЧЕРИЗА- ЦИИ ПРОЦЕССОВ"..................................................6 Лабораторная работа 3 "ИССЛЕДОВАНИЕ ПРИНЦИПОВ РЕАЛИЗАЦИИ ПРОЦЕССОВ И ОЧЕРЕДЕЙ МНОГОЗАДАЧНОГО ЯДРА".......................9 Лабораторная работа 4 "ИССЛЕДОВАНИЕ СИСТЕМНЫХ ОЧЕРЕДЕЙ МНО- ГОЗАДАЧНОГО ЯДРА...............................................15 Лабораторная работа 5 "ИССЛЕДОВАНИЕ МЕТОДОВ СИНХРОНИЗАЦИИ ПРОЦЕССОВ".....................................................19 Лабораторная работа 6 "ИССЛЕДОВАНИЕ МЕТОДОВ БУФЕРИЗАЦИИ СО- ОБЩЕНИЙ".......................................................27 Лабораторная работа 7 "ИССЛЕДОВАНИЕ МЕТОДА ВЗАИМОДЕЙСТВИЯ ПРОЦЕССОВ С ПОМОЩЬЮ ОЧЕРЕДЕЙ СООБЩЕНИЙ.........................32 Редактор Э.К.Долгатов _____________________________________________________________ Лицензия N 020617 от 10.08.92. Подписано в печать . .96. Формат 60х84 1/16. Бумага тип N 2. Печать офсетная. Усл.печ.л. 3,72. Уч.-изд.л. 4,0. Тираж экз. Зак. N Редакционно-издательский отдел ГЭТУ им.В.И.Ульянова (Ленина) _____________________________________________________________ Ротапринт МГП "Поликом" 197376, Санкт-Петербург, ул.Проф.Попова, 5 - 37 -