Преподаватель
Спонсор: Microsoft
Опубликован: 13.11.2010 | Уровень: для всех | Доступ: свободно
Лекция 12:

Методы синхронизации процессов

Семафоры как общее средство синхронизации

Наиболее простой вид синхронизации действий, выполняемых в двух процессах, - это исполнение действия B в процессе Pj после того, как действие A исполнено в процессе Pi . Рассмотрим, как такую синхронизацию осуществить с помощью семафоров.

Используем семафор flag, инициализированный 0.

Код процесса Pi:

. . . 

A;

signal (flag);

Код процесса Pj:

. . . 

wait (flag);

B;

Общие и двоичные семафоры

Из рассмотренного ясно, что имеется два вида семафоров: общий - целая переменная с теоретически неограниченным значением - и двоичный - целая переменная, значениями которой могут быть только 0 или 1. Преимуществом двоичного семафора является его возможная более простая аппаратная реализация. Например, в системах "Эльбрус" и Burroughs 5000 реализованы команды атомарного семафорного считывания с проверкой семафорного бита.

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

Вариант операции wait (S) для системных процессов ("Эльбрус")

Для системного процесса лишние прерывания нежелательны, и может оказаться важным удерживать процессор за собой некоторое время (например, для быстрого выполнения планирования и диспетчеризации процессов). С этой целью в системе "Эльбрус" реализована, в дополнение к операции ждать (S) русифицированной версии wait(S),операция жуж(S) - "жужжать" на процессоре, т.е. ждать на закрытом семафоре, но не прерываться и не отдавать процессор, пока семафор не будет открыт операцией открыть(S)

Реализация общего семафора с помощью двоичных семафоров

Общий семафор может быть представлен тройкой из двух двоичных семафоров и целой переменной:

binary-semaphore S1 = 1;

binary-semaphore S2 = 0;

int C = начальное значение общего семафора S;

Операция wait:

wait (S1);

C--;

if (C < 0) {

	signal (S1);

	wait (S2);

}

signal (S1);

Операция signal:

wait (S1);

C++;

if (C >= 0) {

	signal (S2);

	};

signal (S1);

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

Решение классических задач синхронизации с помощью семафоров

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

  • ограниченный буфер (bounded buffer problem)
  • читатели – писатели (readers – writers problem)
  • - обедающие философы (dining philosophers problem).

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

Будем использовать три общих семафора:

semaphore full = n;

semaphore empty = 0;

semaphore mutex = 1;

Семафор full сигнализирует о переполнении буфера, empty – об исчерпании буфера, mutex используется для взаимного исключения действий над буфером.

Код процесса-производителя имеет вид:

do {

	. . . 

	сгенерировать элемент в nextp

	. . . 

	wait (full);

	wait (mutex);

	. . .

	добавить nextp к буферу

	. . . 

	signal (mutex);

	signal (empty);

} while (1);

Код процесса-потребителя:

do {

	wait (empty);

	wait (mutex);

	. . .

	взять и удалить элемент из буфера в nextc

	. . . 

	signal (mutex);

	signal (full);

	. . .

	использовать элемент из nextc

	. . .

} while (1);

Поясним использование семафоров. Семафор mutex используется "симметрично"; над ним выполняется пара операций: wait … signal – семафорные скобки. Его роль – чисто взаимное исключение критических секций. Семафор empty сигнализирует об исчерпании буфера. В начале он закрыт, так как элементов в буфере нет. Поэтому при закрытом семафоре empty потребитель вынужден ждать. Открывает семафор empty производитель, после того, как он записывает в буфер очередной элемент. Семафор full сигнализирует о переполнении буфера. В начале он равен n – максимальному числу элементов в буфере. Производитель перед записью элемента в буфер выполняет операцию wait (full),гарантируя, что, если буфер переполнен, записи нового элемента в буфер не будет. Открывает семафор full потребитель, после того, как он освободил очередной элемент буфера.

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

Гульжан Мурсакимова
Гульжан Мурсакимова
На каком этапе графического конвейера происходит отсечение невидимых объектов?
Василий Четвертаков
Василий Четвертаков
Почему следует исключить race condition?
Айрат Хисматуллин
Айрат Хисматуллин
Россия
Дмитрий Карпов
Дмитрий Карпов
Россия, Нижний Новгород