
- •Глава 5
- •5.1. Принципы параллельных вычислений
- •Простой пример
- •Взаимодействие процессов
- •Листинг 5.1. Взаимные исключения
- •5.2. Взаимоисключения
- •Листинг 5.3. Алгоритм Петерсона для двух процессов
- •5.3. Взаимоисключения: аппаратная поддержка
- •Специальные машинные команды
- •5.4. Семафоры
- •5.5. Мониторы
- •5.6. Передача сообщений
- •Синхронизация
- •Принцип работы очереди
- •5.7. Задача читателей/писателей
- •Приоритетное чтение
- •5.8. Резюме, ключевые термины и контрольные вопросы
- •5.9. Pекомендуемая литература
- •5.10. Задачи
Приоритетное чтение
В листинге 5.19 приведено решение задачи с использованием семафоров для варианта, в котором имеются один читатель и один писатель (решение не требует изменений, если имеется много читателей и писателей). Процесс писателя очень прост. Для обеспечения взаимного исключения используется семафор wsem. Когда один писатель записывает данные, ни другие писатели, ни читатели не могут получить к ним доступ. Процесс читателя также использует семафор wsem для обеспечения взаимоисключений. Однако чтобы обеспечить возможность одновременной работы многих читателей, состояние семафора проверяет только читатель, входящий в критический раздел, в котором нет других читателей. Если в критическом разделе уже находится хоть один читатель, то другой читатель приступает к работе, не ожидая семафора wsem. Для отслеживания количества Читателей в критическом разделе используется глобальная переменная readcount, а для гарантии корректного ее обновления — семафор х.
Листинг 5.19. Решение задачи читателей/писателей с использованием семафоров (приоритетное чтение)
int readcount;
semaphore x = 1, wsem =1;
void reader()
{
while(true)
{
wait(x);
readcount++;
if (readcount==l)
. wait(wsem);
signal(x);
READUNIT();
wait(x);
readcount--;
if (readcount==0)
signal(wsem);
signal(x);
}
}
void writer()
{
while(true)
{
wait(wsem);
WRITEUNIT() ;
signal(wsem);
}
}
void main() {
readcount = 0;
parbegin(reader, writer);}
Приоритетная запись
В предыдущем решении приоритетной операцией являлось чтение данных. Если один читатель получил доступ к данным, то возможна ситуация, когда писатель в течение долгого времени не получит возможности внести изменения — пока хотя бы один из читателей будет находиться в критическом разделе.
В листинге 5.20 показано решение, обеспечивающее выполнение следующего условия: ни один читатель не сможет обратиться к данным, если хотя бы один писатель объявил о своем намерении произвести запись. Для этого к имеющимся в программе семафорам и переменным процесса писателя добавлены следующие:
• семафор rsem, запрещающий вход читателей, если хотя бы один писатель объявил о намерении произвести запись;
переменная writecount, обеспечивающая корректность установки значения rsem;
• семафор у, гарантирующий корректность изменения переменной writecount.
Листинг 5.20. Решение задачи читателей/писателей с использованием семафоров (приоритетная запись)
int readcount, writecount;
semaphore x = 1, y=l, z=l,
rsem = 1, wsem = 1;
void reader()
{
while (true)
{
wait (z) ;
wait(rsem);
wait(x) ;
readcount++;
if (readcount==l)
wait(wsem);
signal(x);
signal(rsem);
signal(z);
READUNIT ();
wait(x);
readcount--;
if (readcount==0)
signal(wsem); signal(x);
}
}
void writer()
{
while(true)
{
wait(y);
writecount++;
if (writecount==l)
wait(rsem);
signal(y);
wait(wsem);
WRITEUNIT();
signal(wsem);
wait(y);
writecount--;
if (writecount==0)
signal(rsem);
signal(y);
}
}
Таблица 5.5. Состояния очередей процессов в программе из листинга 5.20
В системе имеются только читатели • Устанавливается wsem • Очередей нет В системе имеются только писатели • Устанавливаются wsem и rsem • Очередь писателей на wsem В системе имеются как читатели, • wsem устанавливается читателем так и писатели; первым выполняется • rsem устанавливается писателем чтение • Все писатели становятся в очередь на wsem • Один читатель становится в очередь на rsem • Остальные читатели становятся в очередь на z В системе имеются как читатели, • wsem устанавливается писателем так и писатели; первой выполняется • rsem устанавливается писателем запись • Все писатели становятся в очередь на wsem • Один читатель становится в очередь на rsem • Остальные читатели становятся в очередь на z |
В листинге 5.21 приведено еще одно решение задачи с приоритетной записью, реализованное с использованием системы передачи сообщений. В этом случае имеется управляющий процесс с правом доступа к совместно используемым данным. Прочие процессы запрашивают право доступа к данным, посылая сообщение управляющему процессу. Запрашивающий процесс получает право доступа посредством ответного сообщения "ОК", а после завершения работы сообщает об этом специальным сообщением finished. У управляющего процесса имеются три почтовых ящика, по одному для каждого типа получаемых им сообщений.
Листинг 5.21. Решение задачи читателей/писателей с использованием системы передачи сообщений
void reader(int i)
{
message rmsg; while(true)
{
rmsg = i;
send(readrequest,rmsg);
receive(mbox[i] ,rmsg);
READUNIT();
rmsg = i;
send(finished,rmsg) ;
}
}
void writer(int j)
{
message rmsg;
while(true)
{
rmsg = i;
send(writerequest,rmsg);
receive(mbox[ j ] ,rmsg);
WRITEUNIT() ;
rmsg = i;
send(finished, rmsg) ;
}
}
void controller ()
{
while(true)
{
if (count > 0)
{
if (!empty(finished))
{
receive(finished,msg);
count++;
}
else if (!empty(writerequest))
{
receive(writerequest,msg);
writer_id = msg.id;
count = count - 100;
}
else if (!empty(readrequest))
{
receive(readrequest,msg);
count--;
send(msg.id,"OK");
}
}
if (count == 0)
{
send(writer_id,"OK");
receive(finished,msg);
count = 100;
}
while(count < 0)
{
receive(finished,msg);
count++;
}
}
}
Первыми управляющий процесс обслужит запросы на запись, давая таким образом приоритет операции записи; кроме того, управляющий процесс обеспечивает выполнение взаимоисключений, для чего используется переменная count, инициализируемая неким числом, которое заведомо больше максимально возможного количества читателей. В нашем примере использовано значение 100. Действия управляющего процесса можно описать следующим образом.
Если count>0, значит, ожидающих писателей нет; активные читатели могут как присутствовать, так и отсутствовать. Управляющий процесс обслуживает сначала все сообщения типа finished, а затем запросы от писателей и читателей.
Если count=0, это означает, что у нас имеется только запрос на запись. Управляющий процесс дает писателю "добро" на выполнение своих действий и ожидает от него сообщения о завершении работы.
Если count<0, значит, писатель сделал запрос и ожидает завершения работы всех активных читателей, так что управляющий процесс при этом принимает только сообщения о завершении работы читателей.