Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС / 1.docx
Скачиваний:
185
Добавлен:
03.06.2014
Размер:
5.4 Mб
Скачать

Многоуровневая очередь

Поскольку процессы в системе могут иметь различную специфику (например, пакетные и интерактивные), на практике в операционных системах очередь готовых к выполнению процессов делится на две очереди:

основная (интерактивные процессы)

фоновая (пакетные процессы).

Каждая очередь имеет свой собственный алгоритм диспетчеризации: основная –RR, фоновая – FCFS.

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

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

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

Многоуровневые аналитические очереди

Для более гибкой диспетчеризации процессов в операционных системах организуются многоуровневые аналитические очереди (multi-level feedback queues),в которых обслуживаются процессы нескольких классов, причем каждый из классов имеет различные кванты времени. Самый быстрый (приоритетный) класс процессов получает минимальный квант. Если процесс не завершается за этот квант времени, ОС перемещает его в очередь процессов другого класса с большей величиной кванта, и т.д. Если процесс не завершается и за самый большой из выделяемых системой квантов времени, ОС перемещает его в класс пакетных процессов, обслуживаемых по стратегии FCFS.

Планирование в Solaris

На рис. 11.14 иллюстрируются принципы планирования в ОС Solaris. Система обслуживает несколько классов процессов, в порядке убывания приоритетов: реального времени, системные, интерактивные и с разделением времени. Более высокоприоритетные процессы планируются и диспетчеризуются первыми. Для каждого класса процессов имеется свой планировщик.

Рис. 11.14. Планирование в Solaris.

Планирование в Windows 2000

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

Таблица 1. реального времени высокий выше нормального нормальный ниже нормального приоритет простаивающего процесса

критический 31 15 15 15 15 15

наивысший 26 15 12 10 8 6

выше нормального 25 14 11 9 7 5

нормальный 24 13 10 8 6 4

ниже нормального 23 12 9 7 5 3

низший 22 11 8 6 4 2

простаивающий 16 1 1 1 1 1

Вопрос 14 История синхронизации

Методы синхронизации процессов рассматривались еще в 1960-х гг. в пионерской работе Э. Дейкстры [17]. Было отмечено, что совместный доступ параллельных процессов к общим данным может привести к нарушению их целостности. Поддержание целостности общих данных требует реализации и использования механизмов упорядочения работы взаимодействующих процессов (или потоков).

Анализ проблемы производитель – потребитель с точки зрения синхронизации по общему буферу

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

Вспомним представление ограниченного буфера на языке Си (см. "Методы взаимодействия процессов ") и расширим его переменной counter :

#define BUFFER_SIZE 1000 /* или другое конкретное значение */

typedef struct {

. . .

} item;

item buffer[BUFFER_SIZE];

int in = 0;

intout= 0;

intcounter= 0;

Теперь модифицируем реализации процесса-производителя и процесса-потребителя (см. "Методы взаимодействия процессов ") , добавив соответствующие изменения переменной counter:

Процесс-производитель:

item nextProduced; /* следующий генерируемый элемент */

while (1) { /* бесконечный цикл */

while (counter == BUFFER_SIZE)

; /* ждать, пока буфер переполнен */

buffer[in] = nextProduced; /* генерация элемента */

in = (in + 1) % BUFFER_SIZE;

counter++;

}

Процесс-потребитель:

item nextConsumed; /* следующий используемый элемент */

while(1) { /* бесконечныйцикл */

while(counter== 0)

; /* ждать, пока буфер пуст */

nextConsumed = buffer[out]; /* использование элемента */

out = (out + 1) % BUFFER_SIZE;

counter--;

}

Возникает вопрос: насколько корректны модифицированные алгоритмы, использующие переменную counter ? Не вполне. Проблема в том, что counter фактически является общим ресурсом, к которому одновременно обращаются два параллельных процесса. Если при этом обращение произойдет одновременно, то переменная counter может в итоге оказаться в некорректном состоянии. Поэтому необходимо, чтобы каждый из процессов при увеличении или уменьшении ее значения имел бы к ней монопольный доступ, и другой процесс не мог бы в это время "испортить" значение переменной. Иными словами, операции counter++ и counter— должны выполняться атомарно (см. лекцию 9). Напомним, что атомарная операция – это такая операция, которая должна быть выполнена полностью, без каких-либо прерываний; при этом операция, выполняемая одним из процессов, должна быть неделимой, с точки зрения другого процесса.

Операции count++ и count— могут быть реализованы на языке ассемблерного уровня следующим образом:

count++:

register1 = counter

register1 = register1 + 1

counter = register1

count--:

register1 = counter

register1 = register1 - 1

counter = register1

где register1 – регистр аппаратуры.

Проблема в том, что если и производитель, и потребитель пытаются изменить переменную counter одновременно, то указанные ассемблерные операторы тоже должны быть выполнены совместно (interleaved).

Рассмотрим эффект interleaving на конкретном примере. Предположим, что начальное значение переменной counter в некоторый момент равно 5. Исполнение процессов в совместном режиме (interleaving) может привести к следующему эффекту:

производитель: register1 = counter (register1 = 5)

производитель: register1 = register1 + 1 (register1 = 6)

потребитель: register2 = counter (register2 = 5)

потребитель: register2 = register2 – 1 (register2 = 4)

производитель: counter = register1 (counter = 6)

потребитель: counter = counter2 (counter = 4)

Таким образом, значение counter в итоге может оказаться равным 6 или 4, в то время как правильное значение counter равно 5.

Ситуация, при которой взаимодействующие процессы могут параллельно (одновременно) обращаться к общим данным, называется конкуренцией за общие данные (race condition).Для предотвращения подобных ситуаций процессы следует синхронизировать.

Соседние файлы в папке ОС