- •5. Взаимодействие и синхронизация процессов
- •5.1. Взаимодействие процессов (Лекция 9)
- •5.1.1. Способы взаимодействия процессов
- •5.1.1.1. Проблема синхронизации
- •5.1.1.2. Критические секции, средства коммуникации процессов
- •5.1.1.3. Способы взаимодействия процессов, понятия взаимного исключения, взаимной блокировки, голодания процессов
- •5.1.2. Взаимные исключения
- •5.1.2.1. Требования к взаимным исключениям
- •5.1.2.2. Алгоритмы Деккера и Петерсона реализации взаимного исключения
- •5.2. Семафоры и другие средства синхронизации (Лекция 10)
- •5.2.1. Синхронизация задач с помощью семафоров
- •5.2.1.1. Семафоры Дейкстры
- •5.2.1.2. Условная синхронизация с помощью семафоров
- •5.2.1.3. Планирование очереди процессов, ожидающих у семафора
- •5.2.2. Другие средства синхронизации: счётчики событий, секвенсоры, мониторы, передача сообщений
- •5.2.2.1. Счетчики событий и секвенсоры
- •5.2.2.2. Объекты синхронизации, регламентированные posix
- •5.2.2.3. Мониторы Хоара
- •5.2.2.4. Передача сообщений
- •5.3. Классические проблемы межпроцессного взаимодействия (Лекция 11)
- •5.3.1. Проблема "обедающих философов"
- •5.3.1.1. Описание проблемы "обедающих философов"
- •5.3.1.2. Решение (алгоритм) проблемы "обедающих философов"
- •5.3.2. Проблема "спящего брадобрея" (задача о парикмахерской)
- •5.3.2.1. Описание задачи о парикмахерской
- •5.3.2.2. Решение (алгоритм) задачи о парикмахерской
- •5.3.3. Задача "читателей и писателей"
- •5.3.3.1. Описание задачи читателей и писателей
- •5.3.3.2. Решение (алгоритм) задачи читателей и писателей
- •5.4. Взаимоблокировки (Лекция 12)
- •5.4.1. Возникновение взаимоблокировок
- •5.4.1.1. Проблема взаимоблокировок
- •5.4.2. Устранение взаимоблокировок
- •5.4.2.1. Запрещение запуска процесса
- •5.4.2.2. Запрет выделения ресурса
- •5.4.3. Обнаружение взаимоблокировок
- •5.4.3.1. Алгоритм обнаружения взаимоблокировок
- •5.4.3.2. Действия, выполняемые после обнаружения взаимоблокировки
5.3.1.2. Решение (алгоритм) проблемы "обедающих философов"
Хорошее решение:
#defineN5 //количество философов
#define LEFT (i+N+1)%N //номер левого соседа
#define RIGHT (i=N-1)%N //номер правого соседа
#define THINKING 0 //думает
#define HUNGRY 1 //голоден
#define EATING 2 //ест
typedefintsemaphore;
intstate[N]; //массив для отслеживания состояний каждого философа
semaphoremutex=1;
semaphoreS[N]; //каждому философу по семафору
//-------------------------------------------------------------------------------------------------
void philosopher (int i) //i – номер философа от 0 до N-1
{
while(1)
{
think();
take_forks(i);
eat();
put_forks(i);
}
}
void take_forks (int i)
{
wait(mutex); //вход вCS
state[i]=HUNGRY; //фиксация наличия голодного философа
test(i); //фиксация наличия голодного философа
release(mutex); //выход изCS
wait(S[i]); //блокировка, если вилок не досталось
}
void test (int i)
{
if(state[i]==HUNGRY && state[LEFT)!=EATING)
{
state[i]=EATING;
signal(S[i]);
}
}
Здесь философ как бы сам себя пропускает, открывая семафор. Если же условие ложно, семафор не откроется, и процедура take_forksбудет блокирована.
void put_forks (int i)
{
wait(mutex); //вход в CS
state[i]=THINKING; //философ перестал есть
test(LEFT); // проверить, могут ли есть
test(RIGHT); //соседи слева и справа
release (mutex); //выход из CS
}
5.3.2. Проблема "спящего брадобрея" (задача о парикмахерской)
5.3.2.1. Описание задачи о парикмахерской
В парикмахерской есть один брадобрей, его кресло и nстульев для посетителей. Если желающих побриться нет, брадобрей сидит в своем кресле и спит. Если в парикмахерскую приходит клиент, а брадобрей спит, клиент будит его. Если же брадобрей занят, то клиент садится на стул или уходит, если все стулья заняты. Необходимо запрограммировать брадобрея и посетителей.
Предлагаемое решение:
Используются три семафора:
Customers– для подсчета ожидающих посетителей (без того, который уже стрижется);
Barbers– количество простаивающих в ожидании брадобреев (0 или 1);
Mutex– для реализации взаимного исключения.
Также используется переменная waitingдля подсчета ожидающих посетителей. Она является копиейcustomersи нужна для того, чтобы заглядывающий клиент мог сосчитать количество занятых стульев и уйти, если мест уже нет. При отсутствии неблокирующего ожидания на семафоре копияcustomers– единственный выход.
5.3.2.2. Решение (алгоритм) задачи о парикмахерской
#defineCHAIRS5 //количество стульев
typedef int semaphore;
semaphore customers=0;
semaphore barbers=0;
semaphore mutex=1;
int waiting=0;
void barber(void)
{
while(1)
{
wait(customers); //ждать посетителей
wait(mutex); //вход вCS
waiting--; //ждет уже на одного меньше
signal(barbers); // на одного больше брадобрея доступно
release(mutex); // выход из СS
cut_hair(); //обслуживание – внеCS
}
}
void customer(void)
{
wait(mutex); //вход в CS
if(waiting<CHAIRS)
{
//если есть места
waiting++; //ожидающих на 1 больше
signal(customers); //разбудить брадобрея, если надо
release(mutex); //выход изCS
wait(barbers); //ждать, пока брадобрей не освободится
get_haircut(); //постричься
}
elserelease(mutex); //много посетителей – уйти, освободитьmutex
}
Приходя, клиент запрашивает mutex; если придут сразу два клиента или более, только один из них сможет выполнять процедуруcustomer.
Если свободный стул есть, посетитель увеличивает число ожидающих и активизирует брадобрея. Но начать стричься он не может, пока брадобрей занят. Брадобрей, приходя на работу, сначала блокируется на семафоре customers. Когда придет клиент и активизирует его, брадобрей захватитmutexи уменьшит число ожидающих, усадив одного клиента в кресло.
Замечание: не смотря на отсутствие передачи данных между процессами, рассмотренные задачи являются задачами межпроцессорного взаимодействия, т.к. они требуют синхронизации действий процессов.
Это в некоторой степени относится и к следующей задаче.