Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
5 семестр / Литература / лекция4.Синхронизация.pptx
Скачиваний:
12
Добавлен:
18.02.2023
Размер:
695.79 Кб
Скачать

ПРОЦЕССЫ И ПОТОКИ

СИНХРОНИЗАЦИЯ

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

Два процесса используют общий буфер фиксированного размера.

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

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

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

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

Для отслеживания количества записей в буфере нам потребуется переменная count.

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

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

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

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

#define N 100

/*

количество мест для записей в буфере */

int count = 0;

/* количество записей в буфере */

void producer(void)

 

 

{

 

 

int item;

 

 

while (TRUE) {

/*

бесконечное повторение */

item = produce_item( );

/*

генерация новой записи */

if (count == N) sleep( );

/*

если буфер полон, заблокироваться */

insert_item(item);

/*

помещение записи в буфер */

count = count + 1;

/*

увеличение счетчика записей в буфере */

if (count == 1) wakeup(consumer); /*

был ли буфер пуст? */

}

 

 

}

 

 

void consumer(void)

 

 

{

 

 

int item;

 

 

while (TRUE) {

/*

бесконечное повторение */

if (count == 0) sleep();

/*

если буфер пуст, заблокироваться */

item = remove_item( );

/*

извлечь запись из буфера */

count = count− 1;

/*

уменьшение счетчика записей в буфере */

if (count == N − 1) wakeup(producer);

/* был ли буфер полон? */

consume_item(item);

/*

распечатка записи */

}

 

 

}

 

 

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

Причиной появления состязательной ситуации может стать свободный доступ к счетчику count. Как следствие может сложиться следующая ситуация.

Буфер пуст, и потребитель только что считал показания count, чтобы увидеть, что его значение равно 0. В этот самый момент планировщик решает временно приостановить выполнение процесса потребителя и возобновить выполнение процесса производителя. Производитель помещает запись в буфер, увеличивает значение счетчика count и замечает, что теперь оно равно 1.

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

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

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

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

Рано или поздно производитель заполнит буфер и тоже перейдет в заблокированное состояние. И оба процесса впадут в вечную спячку.

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ

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

Быстро устранить проблему позволит изменение правил за счет добавления бита ожидания активизации. Этот бит устанавливается, когда в отношении процесса, который не находится в состоянии бездействия, вызывается процедура wakeup. Затем, когда процесс попытается заблокироваться при установленном бите ожидания активизации, этот бит снимается, но процесс не блокируется. Бит ожидания активизации становится своеобразной копилкой, хранящей сигналы активизации. Потребитель снимает бит ожидания активизации в каждой итерации цикла.

СЕМАФОРЫ

В 1965 году Дейкстра предложил учредить новый тип переменной — семафор (semaphore). Значение семафора может быть равно 0, что будет свидетельствовать об отсутствии сохраненных активизаций, или иметь какое-нибудь положительное значение, если ожидается не менее одной активизации.

Две операции с семафорами, которые сейчас обычно называют down и up. Операция down выясняет, отличается ли значение семафора от 0. Если отличается, она уменьшает это значение на 1 (то есть использует одну сохраненную активизацию) и продолжает свою работу.

Если значение равно 0, процесс приостанавливается, не завершая в этот раз операцию down. И проверка значения, и его изменение, и, возможно, приостановка процесса осуществляются как единое и неделимое атомарное действие. Тем самым гарантируется, что с началом семафорной операции никакой другой процесс не может получить доступ к семафору до тех пор, пока операция не будет завершена или заблокирована.

СЕМАФОРЫ

Операция up увеличивает значение, адресуемое семафором, на 1. Если с этим семафором связаны один или более приостановленных процессов, способных завершить ранее начатые операции down, система выбирает один из них (к примеру, произвольным образом) и позволяет ему завершить его операцию down.

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

Ни один из процессов не может быть заблокирован при выполнении операции up, равно как ни один из процессов не может быть заблокирован при выполнении wakeup в предыдущей модели.

ЗАДАЧА ПРОИЗВОДИТЕЛЯ И ПОТРЕБИТЕЛЯ, РЕШАЕМАЯ С ПОМОЩЬЮ СЕМАФОРОВ

В этом решении используются три семафора:

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

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

третий называется mutex, он предотвращает одновременный доступ к буферу производителя и потребителя.

Семафор full изначально равен 0, семафор empty изначально равен количеству мест в буфере, семафор mutex изначально равен 1.

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

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