Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
03-21-12 Параллельные вычисления.DOC
Скачиваний:
5
Добавлен:
23.08.2019
Размер:
322.56 Кб
Скачать

Листинг 7.1. Алгоритм Деккера для двух процессов

Boolean flag [2];

int turn;

void P Ø ()

{

while (true)

{

flag [Ø] = true;

while (flag [1])

if (turn ==1)

{

flag [Ø] = false;

while (turn ==1) /* WAIT*/;

flag [Ø] = true;

}

/* критический раздел */

turn = 1;

flag [Ø] = false;

/*остальной код */

}

}

void P1 ()

{

while (true);

{

flag [1] = true;

while (flag [Ø])

if (turn ==Ø)

{

flag [1] = false;

while (turn == Ø); /* WAIT */

Flag[1] = true;

}

/* критический раздел */

turn = 0;

flag [1] = false;

/* остальной код */

}

}

void main ()

{

flag [Ø] = false;

flag [1] = false;

turn = 1;

parbegin (P Ø,P1);

}

7.2.2. Алгоритм Петерсона

Алгоритм Деккера решает задачу взаимных исключений, но достаточно сложно, и вдобавок тяжело доказать его корректность. В 1981 году Петерсон (Peterson) предложил более изящное и простое решение проблемы взаимных исключений. Как и раньше, глобальная сменная flag указывает на положение каждого процесса по отношению к взаимоисключениям, а глобальная переменная turn решает конфликты одновременности. При исполнении пролога критической секции процесс Pi заявляет о своей готовности выполнить критический участок и одновременно предлагает другому процессу приступить к его выполнению. Если оба процесса подошли к прологу практически одновременно, то они оба объявят о своей готовности и предложат выполняться друг другу. При этом одно из предложений всегда следует после другого. Тем самым работу в критическом участке продолжит процесс, которому было сделано последнее предложение.

Листинг 7.2. Алгоритм Петерсона для двух процессов

boolean flag[2];

int turn;

void PØ()

{

while (true)

{

flag[Ø] = true;

turn = 1;

while (flag[1] && turn == 1); /* ждать */

/* критический раздел */

flag[Ø] = false;

/* остальной код */;

}

}

void p1()

{

while (true)

{

flag[1] = true;

turn = 0;

while (flag[Ø]) && turn == 0);/* ждать */

/* критический раздел */

flag[1] = false;

/* остальной код */

}

}

void main()

{

flag[Ø] = false;

flag[1] = false;

turn = 1;

parbegin(P Ø,P1);

}

Выполнение условий взаимоисключения легко доказать. Рассмотрим процесс Р0. После того как flag[0] установленный в true, Р1 войти в критический раздел не может. Если же Р1 уже находится в критическом разделе, то flag[1] = true и для Р0 вход в критический раздел заблокирован. В данном случае взаимное блокирование предотвращено. Предположим, что Р0 заблокирован в своем цикле whіle. Это означает, что flag[1] = true, а turn = 1. Р0 может войти в критический раздел, когда либо flag[1] становится равным false, либо turn становится равным 0. Рассмотрим три исчерпывающих случая.

1. Р1 не намерен входить в критический раздел. Такой случай невозможен, поскольку при этом выполнялось бы условие flag[1] = false.

2. Р1 ожидает вход в критический раздел. Такой случай также невозможным, поскольку, если turn = 1, то Р1 способен войти в критический раздел.

3. Р1 циклически использует критический раздел, монополизируя доступ к нему. Этого не может произойти, поскольку Р1 вынужден перед каждой попыткой вхождения в критический раздел дать такую возможность процессу Р0, устанавливая значение turn равным 0.

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