Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций 2.doc
Скачиваний:
1
Добавлен:
01.05.2025
Размер:
446.98 Кб
Скачать

7.2.2 Семафоры

7.2.2.1. Простые семафоры

Семафор - это защищенная общая переменная, значение которой можно опрашивать и менять только при помощи специальных операций wait и signal и операции инициализации init. Двоичные семафоры могут принимать только значения 0 и 1. Семафоры со счетчиками могут принимать неотрицательные целые значения.

Операция wait(s) над семафором s состоит в следующем:

если s > 0

то s:=s-1

иначе (ожидать на s)

Операция signal(s) заключается в том, что:

если (имеются процессы, которые ожидают на s)

то (разрешить одному из них продолжить работу)

иначе s:=s+1

Операции являются неделимыми. Критические участки процессов обрамляются операциями wait(s) и signal(s). Если одновременно несколько процессов попытаются выполнить операцию wait(s), то это будет разрешено только одному из них, а остальным придется ждать.

7.2.2.2 Семафоры со счетчиками

Семафоры со счетчиками используются, если некоторые ресурс выделяется из множества идентичных ресурсов. При инициализации такого семафора в его счетчике указывается число элементов множества. Каждая операция wait(s) уменьшает значения счетчика семафора s на 1, показывая, что некоторому процессу выделен один ресурс из множества. Каждая операция signal(s) увеличивает значение счетчика на 1, показывая, что процесс возвратил ресурс во множество. Если операция wait(s) выполняется, когда в счетчике содержится нуль (больше нет ресурсов), то соответствующий процесс ожидает, пока во множество не будет возвращен освободившийся ресурс, то есть пока не будет выполнена операция signal.

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

7.2.4 Мониторы

7.2.4.1 Простые мониторы

Формально монитор (monitor) представляет собой конструкцию языка программирования, такую же, как объект в объектно-ориентированном программировании. Монитор может рассматриваться как модуль, содержащий переменные и процедуры. Доступ к переменным можно получить только путем вызова одной из процедур монитора. В этом смысле монитор очень похож на объект. Объект также имеет свои защищенные данные, доступ к которым можно получить только через методы, реализованные в этом объекте. Разница между мониторами и объектами состоит в том, что монитор разрешает выполнение процедуры только одному процессу в каждый момент времени. Другими словами, если процедура, содержащаяся в мониторе, выполняется процессом А (мы говорим, что А вошел в монитор) и процесс В также вызывает одну из процедур монитора, В будет блокирован до завершения выполнения А (то есть до тех пор, пока А не покинет монитор).

В качестве примера рассмотрим простой монитор для защиты целой переменной (листинг 7.1). Монитор содержит одну закрытую (private) переменную count, доступ к которой можно получить только через три открытых (public) процедуры — чтения текущего значения, увеличения на единицу и уменьшения. Конструкция монитора гарантирует, что любой процесс, который вызывает одну из этих процедур, получит атомарный доступ к внутренним данным монитора.

Листинг 7.1. Монитор, предохраняющий целое число от параллельного доступа

monitor Counter { private:

int count = 0; public:

int value() { return count; }

void incr() { count = count + 1;}

void decr() { count = count - 1;}

}