Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ОС_Методические указания

.pdf
Скачиваний:
41
Добавлен:
11.03.2016
Размер:
378.26 Кб
Скачать

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

ПРОЧИТАТЬ(ЗАПИСЬ)

 

Программа -

Устройство ввода

пользователь

 

Буфер (очередь из N позиций)

Рис. 3.4. Схема буферного ввода данных.

Листинг 3.4. Алгоритм буферного ввода данных.

ПРОЧИТАТЬ(ЗАПИСЬ) {--вызов супервизора--}

If not БУФЕР_ПУСТОЙ then begin

ИЗЪЯТЬ(ЗАПИСЬ,БУФЕР); <Запустить передачу, если необходимо>

end

else

begin

<Запустить передачу, если необходимо>; ЖДАТЬ;

end

{--обработчик прерывания--} if not БУФЕР_ПОЛНЫЙ

then <Запустить передачу>; if ОЖИДАНИЕ

then <Возобновить чтение>

 

ЗАПИСАТЬ(ЗАПИСЬ)

Устройствовывода

Программа-

пользователь

 

Буфер(очередьизNпозиций)

Рис. 3.5. Схема буферного вывода данных.

Листинг 3.5. Алгоритм буферного вывода данных.

ЗАПИСАТЬ(ЗАПИСЬ) {--вызов супервизора--}

If not БУФЕР_ПОЛНЫЙ then begin

ПОМЕСТИТЬ(ЗАПИСЬ,БУФЕР);

- 21 -

<Запустить передачу, если необходимо>

end

else

begin

<Запустить передачу, если необходимо>; ЖДАТЬ;

end

{--обработчик прерывания--} if not БУФЕР_ПУСТОЙ

then <Запустить передачу>; if ОЖИДАНИЕ

then <Возобновить запись>

В приведенных выше программах «если необходимо» означает «если передача уже не осуществляется».

3.4. ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ

1.Реализуйте на каком-либо алгоритмическом языке высокого уровня очередь (рис. 3.3), предназначенную для работы с записями длиной в слово. Реализация должна предусматривать следующие примитивы:

function put_word(rec:word):boolean;

Назначение: Занести запись rec в очередь.

Входные параметры:

rec - запись длиной в слово, заносимая в очередь.

Выходные параметры: нет. Выдаваемые значения:

true - операция завершилась успешно,

false - очередь переполнена, операция прервана.

function get_word(var rec:word):boolean;

Назначение: Извлечь запись из очереди.

Входные параметры: нет Выходные параметры:

rec - запись длиной в слово, извлекаемая из очереди.

Выдаваемые значения:

true - операция завершилась успешно, false - очередь пуста, операция прервана.

2.Реализуйте на каком-либо алгоритмическом языке высоко уровня очередь, предназначенную для работы с записями произвольной длины. Реализация должна предусматривать следующие примитивы:

function put_record(const rec; n:integer):boolean;

Назначение: Занести запись rec в очередь.

Входные параметры:

rec - запись длиной n байт, заносимая в очередь; n - длина записи в байтах.

Выходные параметры: нет. Выдаваемые значения:

true - операция завершилась успешно,

- 22 -

false - очередь переполнена, операция прервана.

function get_record(var rec; m:integer):integer;

Назначение: Извлечь запись из очереди.

Входные параметры:

m - максимальная длина буфера rec байтах.

Выходные параметры:

rec - буфер, куда будет копироваться извлекаемая запись.

Выдаваемые значения:

«0» - очередь пуста, операция прервана;

«-1» - длина m буфера оказалась недостаточной для размещения извлекаемой записи; положительное значение является длиной извлеченной записи в случае успешного завершения операции.

3.Качество системы может быть улучшено путем организации всех медленных процедур вводавывода через буферы на диске. Если эти буферы достаточно большие, можно опережать обмен с медленными периферийными устройствами (например, с принтерами) за счет записи на

диск или чтения с него.

ЗАПИСАТЬ_СТРОКУ

 

 

 

 

 

 

 

 

 

 

 

 

Буфер записи

 

Буфер печати

 

 

 

 

 

 

Буфер на диске

Такой режим функционирования называется спулингом.

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

- 23 -

РАБОТА 4. ПРОЦЕССЫ. МЕХАНИЗМЫ СИНХРОНИЗАЦИИ ПРОЦЕССОВ

Целью работы является ознакомление с понятием процессов, способами их взаимодействия и механизмами синхронизации совокупности процессов.

4.1. ПОНЯТИЕ ПРОЦЕССА

Понятие процесса дает возможность моделировать активное состояние непрерывного выполнения программы на машине.

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

Определение 4.1

Событием назовем состояние машины, наблюдаемое в некоторый момент времени t .

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

чим beg(a) и end(a) ; имеем beg(a) end(a) .

Определение 4.2

Последовательность действий a1 ,a2 , ,ai , , для каждого элемента которой beg(ai ) end(ai 1 ) , называется последовательным процессом или просто процессом.

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

Определение 4.3

Контекстом процесса назовем ту информацию, которую действия процесса могут проверять или изменять.

Контекст процесса, связанного с выполнением программы, включает:

контекст процессора;

контекст памяти, или рабочее пространство;

совокупность атрибутов процесса, которая содержит следующие характеристики:

имя процесса, которое служит для его идентификации и обычно представляет некоторый уникальный номер;

приоритет процесса, который служит для упорядочения выделения процессора процессам;

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

4.2. ВЗАИМОДЕЙСТВИЕ СОВОКУПНОСТИ ПРОЦЕССОВ

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

Определение 4.4

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

- 24 -

Контексты разных процессов могут иметь общие части.

Определение 4.5

Два процесса называются независимыми, если их контексты не пересекаются.

Пусть имеются две разные программы P и Q со своими сегментами процедур и данных. Соответствующие им процессы обозначим p и q. Выполнение совокупности процессов (p,q) может происходить следующими путями, представленными на рис. 4.1.

 

 

 

 

p

 

 

 

 

 

(1)

 

 

 

 

 

 

 

 

q

p

 

 

 

 

 

 

 

 

 

p

(2)

 

 

 

q

 

 

 

 

q

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

p

(3)

q

Рис. 4.1. Совместное выполнение совокупности процессов.

По схеме 1 сначала полностью выполняется один процесс, а затем - второй. Схема этого типа является схемой последовательного выполнения процессов p и q. Она описывается неравен-

ством end( p) beg(q) .

По схеме 2 поочередно выполняется последовательность инструкций p, потом последовательность инструкций q, затем вновь последовательность следующих инструкций p и т.д., пока не окончатся оба процесса. Эта схема - схема псевдопараллельного выполнения. Процессы выполняются на одном процессоре.

По схеме 3 оба процесса выполняются одновременно на различных процессорах. Схемы 2-го и 3-го типов описываются неравенствами end( p) beg(q) и end(q) beg( p) .

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

Определение 4.6

Ресурс, который допускает обслуживание только одного пользователя за один раз, называется критическим ресурсом.

В схеме 2 взаимодействия процессов процессор является критическим ресурсом для процессов p и q.

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

Приведем пример критического участка. Пусть имеются два процесса p и q, каждый из которых изменяет значение одной общей переменной n. Например, переменной n может быть со-

- 25 -

стояние банковского счета, на который p и q осуществляют вклады. Запишем соответствующие действия в программах p и q:

(процесс p) Ap: n: n 10; (процесс q) Aq: n: n 20 .

Распишем теперь эти действия в виде инструкций, обозначая соответствующие регистры

Rp и Rq.

Листинг 4.1

ПРОЦЕСС p

;загрузить n в Rp

ПРОЦЕСС q

(1)

mov Rp,n

(1') mov Rq,n

(2)

add Rp,10 ;Rp:=Rp+10

(2') add Rq,20

(3)

mov n,Rp

;заслать Rp в n

(3') mov n,Rq

Если в результате функционирования этих двух процессов действия будут выполнены в следующем порядке: 1,1',2,2',3,3', то счет увеличится лишь на 20 единиц, а 10 единиц будут потеряны. Чтобы избежать этого, действия Ap и Aq должны выполняться в режиме взаим-

ного исключения. Эти действия образуют критические секции.

Другим характерным примером взаимодействия процессов является буферный вводвывод, в котором два процесса, выполняемых центральным процессором и каналом вводавывода, обмениваются информацией через общий буфер. Здесь процессы, находящиеся в отношении кооперации для выполнения общей цели - ввода-вывода информации, «конфликтуют» между собой за обладание разделяемым критическим ресурсом - буфером ввода-вывода. Конфликты могут выражаться в следующем:

попытка чтения из буфера, в котором нет ни одной записи;

попытка записи в переполненный буфер;

попытка чтения данных из буфера одним процессом, в то время как другой процесс выполняет запись в буфер.

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

В общем случае проблему взаимного исключения можно сформулировать в следующей форме. Пусть ( p1 , , pn ) - последовательность циклических процессов, программа каждого из которых содержит критическую секцию (листинг 4.2).

Листинг 4.2

<инициализация> {--выполняется один раз до начала всех процессов}

ПРОГРАММА ПРОЦЕССА pi while true do

begin

<ПРОЛОГ>; <КРИТИЧЕСКАЯ СЕКЦИЯ>; <ЭПИЛОГ>;

<ОСТАВШАЯСЯ ЧАСТЬ ПРОГРАММЫ>;

end

4.3. СИНХРОНИЗАЦИЯ ПРОЦЕССОВ

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

- 26 -

если один или несколько процессов хотят обратиться к своим критическим участкам, то по меньшей мере один из них должен в конце концов получить разрешение войти в свой критический участок;

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

Блокировка памяти

Одним из способов реализации взаимного исключения является синхронизация с помощью элементарных приемов нижнего уровня - блокировки памяти. Здесь взаимное исключение реализуют аппаратно, сделав операции над памятью неделимыми. То есть если каждый из двух процессов пытается поместить какое-то значение в одну и ту же ячейку, то спор разрешается аппаратурой: одному процессу разрешается выполнить операцию засылки немедленно, а другому приходится ждать, пока первый не кончит.

Рассмотрим в качестве примера задачу синхронизации (листинг 4.2) для двух процессов. Одним из возможных решений этой задачи является алгоритм Деккера (листинг 4.3).

Листинг 4.3. Алгоритм Деккера.

{--инициализация--}

var c1,c2, ОЧЕРЕДЬ: integer; c1:=0; c2:=0; ОЧЕРЕДЬ:=1;

ПРОЦЕСС p1

ПРОЦЕСС p2

{--пролог--}

{--пролог--}

c1:=1;

c2:=1;

while c2=1 do

while c1=1 do

if ОЧЕРЕДЬ=2 then

if ОЧЕРЕДЬ=1 then

begin

begin

c1:=0;

c2:=0;

while ОЧЕРЕДЬ=2

while ОЧЕРЕДЬ=1

do;

do;

c1:=1;

c2:=1;

end;

end;

<КРИТИЧЕСКАЯ СЕКЦИЯ>

<КРИТИЧЕСКАЯ СЕКЦИЯ>

{--эпилог--}

{--эпилог--}

c1:=0;

c2:=0;

ОЧЕРЕДЬ:=2;

ОЧЕРЕДЬ:=1;

<ОСТАВШАЯСЯ ЧАСТЬ>

<ОСТАВШАЯСЯ ЧАСТЬ>

В этом алгоритме c1=1, когда p1 хочет войти в свою критическую секцию; c2=1, когда p2 хочет войти в свой критический участок, а переменная ОЧЕРЕДЬ указывает, чья очередь по-

пытаться войти при условии, что оба процесса хотят выполнить свои критические участки.

Проверка и установка

Для реализации взаимного исключения процессов во многих машинах имеются аппаратные операции, которые легче в использовании и более эффективны, чем простая и неделимая операция над памятью. Одна из таких операций - «проверка_и_установка».

К операции «проверка_и_установка» обращаются с двумя параметрами: ЛОКАЛЬНЫЙ и ОБЩИЙ. Операция берет значение параметра ОБЩИЙ и присваивает его переменной ЛОКАЛЬНЫЙ, а затем устанавливает в переменной ОБЩИЙ значение 1. Главное свойство этой операции

- 27 -

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

Переменная ОБЩИЙ разделяется между процессами, которые подлежат синхронизации по отношению к некоторому критическому ресурсу. У каждого процесса есть своя собственная переменная ЛОКАЛЬНЫЙ. Предполагается также, что в этой машине реализована блокировка памяти, т.е. операция присвоения переменной ОБЩИЙ значения неделима.

Листинг 4.4. Взаимное исключение с помощью операции «проверка_и_установка»

{--инициализация--} var

ОБЩИЙ: integer;

ПРОГРАММА ПРОЦЕССА pi

var

ЛОКАЛЬНЫЙ: integer; while true do

begin

{--пролог--}; ЛОКАЛЬНЫЙ:=1; while ЛОКАЛЬНЫЙ=1

do проверка_и_установка(ЛОКАЛЬНЫЙ,ОБЩИЙ); <КРИТИЧЕСКАЯ СЕКЦИЯ>; {--эпилог-->; ОБЩИЙ:=0;

<ОСТАВШАЯСЯ ЧАСТЬ ПРОГРАММЫ>;

end.

Монитор Хоара

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

Базовыми примитивами монитора являются следующие процедуры:

ЖДАТЬ - блокирует процесс и ставит его в очередь ожидания;

ПУСТО - логическая функция (выдает true, если очередь ожидания пуста);

СИГНАЛИЗИРОВАТЬ - если не ПУСТО, то активизирует один процесс из очереди ожидания. Процесс, активизируемый примитивом СИГНАЛИЗИРОВАТЬ, начинает свою работу с

инструкции, идущей сразу же за примитивом ЖДАТЬ, который его блокировал.

Для описания монитора удобнее всего использовать методы объектно-ориентированного программирования, что мы в дальнейших примерах и задачах и будем делать. Базовые примитивы монитора будем считать заданными в качестве методов объекта TMonitor:

- 28 -

Листинг 4.5. Объявление монитора

type

TMonitor=object private

<внутренние переменные и очереди ожидания>; protected

procedure ЖДАТЬ;

procedure СИГНАЛИЗИРОВАТЬ; function ПУСТО: boolean;

end;

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

Для решения этой задачи объявим монитор, являющийся наследником объекта TMonitor (листинг 4.6).

Листинг 4.6

type

TBufMonitor=object(TMonitor) private

ЗАВЕРШЕН: boolean; public

procedure ИНИЦИАЛИЗИРОВАТЬ; procedure КОНЕЦ_ЗАПИСИ; procedure НАЧАЛО_ЧТЕНИЯ;

end;

procedure TBufMonitor.ИНИЦИАЛИЗИРОАТЬ; begin

ЗАВЕРШЕН:=false;

end;

procedure TBufMonitor.КОНЕЦ_ЗАПИСИ; begin

ЗАВЕРШЕН:=true; СИГНАЛИЗИРОВАТЬ;

end;

procedure TBufMonitor.НАЧАЛО_ЧТЕНИЯ; begin

if not ЗАВЕРШЕН then ЖДАТЬ;

end;

Здесь переменная состояния ЗАВЕРШЕН сигнализирует о том, занят ли буфер каким-либо процессом. Процедуры КОНЕЦ_ЗАПИСИ и НАЧАЛО_ЧТЕНИЯ должны быть неделимыми.

Монитор используется следующим образом.

- 29 -

Листинг 4.7

{--общая часть--} var m:TBufMonitor;

m.ИНИЦИАЛИЗИРОВАТЬ;

ПРОЦЕСС p

ПРОЦЕСС q

ЗАПИСАТЬ(a);

<начало q>

m.КОНЕЦ_ЗАПИСИ;

m.НАЧАЛО_ЧТЕНИЯ;

<продолжение p>

ПРОЧИТАТЬ(a)

Семафоры

Семафор состоит из счетчика СЧ с целыми значениями и очереди ожидания. При инициализации семафора счетчик принимает начальное значение C0 0 , а очередь пуста. Семафор может управляться только двумя примитивами P и V, которые являются неделимыми; значения счетчика и очередь ожидания недоступны даже для чтения.

Когда некий процесс выполняет примитив P:

СЧ:=СЧ-1;

если СЧ 0, то процесс продолжает работу;

если СЧ<0, то процесс блокируется и становится в очередь ожидания; он остается заблокированным до тех пор, пока примитив P, выполненный другим процессом, не освободит его.

Когда какой-либо процесс выполняет примитив V:

СЧ:=СЧ+1;

если СЧ>0, то процесс продолжает работу;

если СЧ 0, то один процесс удаляется из очереди ожидания и получает разрешение продолжить работу; процесс, который обратился к операции V, тоже может продолжать работу.

4.4. ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ

1. Рассмотрим набор из восьми частично упорядоченных процессов {A,B,C,D,E,F,G,H}, где

end( A) beg(B) ,

end( A) beg(C) , end( A) beg(E) , end(E) beg(F) , end(D) beg(F) , и

end(C) beg(D) ,

end(B) beg(D) ,

end(F) beg(G) ,

end(F) beg(H) . Изобразите

выполнение этой последовательности процессов в виде программы, используя, где возможно, параллелизм процессов. Фрагменты программ, которые могут выполняться параллельно, заключите между ключевыми словами parbegin и parend.

2.Выполните задание 1 при дополнительном ограничении end(E) beg(C) .

3.Пусть имеется следующий алгоритм синхронизации двух процессов с использованием блокировки памяти.

Листинг 4.8

{--общая часть--}

var sw1,sw2: boolean; sw1:=false; sw2:=false;

ПРОЦЕСС 1

ПРОЦЕСС 2

while true do

while true do

begin

begin

while sw2 do;

while sw1 do;

sw1:=true;

sw2:=true;

<критический участок>

<критический участок>

sw1:=false;

sw2:=false;

- 30 -