Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
24
Добавлен:
17.04.2013
Размер:
189.44 Кб
Скачать

6

СПО Лекция 5 [15.07.19]

Лекция 5: Взаимодействующие процессы. Задача взаимного исключения.

  • Взаимодействующие процессы

  • Атомарные операции

  • Программное решение задачи взаимного исключения

Независимые и взаимодействующие процессы

Параллелизм на уровне прикладных программ (процессов) не предполагает их взаимодействия. Конфликты, связанные с доступом к общим ресурсам, решаются внутри ОС и не требуют никаких усилий от программиста. Порядок выполнения программ не имеет значения.

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

Преимущества:

  • пропускная способность (совмещение операций ввода-вывода с вычислениями)

  • возможность распараллеливать вычисления в однопроцессорных и многопроцессорных системах

  • модульность: декомпозиция сложной задачи

Проблемы:

  • синхронизация нитей при доступе к общим ресурсам

  • недетерминированность и неповторяемость многонитевых программ! Следствие: сложность отладки, необходимость в хорошей методике написания таких программ.

Пример 1:

Нить A Нить B

x = 1 x = 2

Каков результат, если x – глобальная переменная?

Пример 2:

Нить A Нить B

a) y = 12

b) x = 1 d) y = 2

c) x = x +y e) y = y + 2

Каков результат, если x и y– глобальные переменные?

d, e, a, b, c: x=13 y = 12

a, b, c, d, e: x=13 y = 4

a, b, c1, d, e, c2: x=5 y = 4

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

Атомарные операции

Операция, которая неделима, непрерываема и, начавшись, обязательно завешается

В большинстве машин атомарными являются операции записи в память и чтения из памяти.

Неатомарными, например, являются операции записи (чтения) переменных типа DOUBLE на машинах с 32 битной архитектурой.

Пример 3: Два процесса добавляют новый элемент в конец линейного списка с глобальными указателями head и tail. Действия:

  • (A) a = new Item();

  • (B) a->next = null;

  • (C) tail->next = a; - это не атомарная операция: читать tail; писать в tail->next

  • (D) tail = a

Последовательность действий:

C1, D1, C2, D2 - все OK

C1, C2, D1, D2 - потеряли элемент, список - OK

C1, C2, D2, D1 - tail указывает на оторванный элемент, последующие добавления в список приведут к созданию списка, на голову которого нет указателя

Пример 4:

Нить A Нить B

i=0; i=0;

while(i<10000) i++; while(i>-10000) i--;

printf(“A wins”); printf(“B wins”);

Кто победит? Кто быстрее!

Есть гарантия, что кто-то выиграет? Нет. Могут крутиться бесконечно!

Если выполняются на отдельных идентичных процессорах, то будут ли крутиться бесконечно? Совсем не факт!

Мораль: с общими переменными надо работать аккуратно.

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

«Критическая секция» – часть кода, которая в любой момент времени может выполняться только одним процессом

unlock lock lock

Критическая секция

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

Если критическая секция заперта, то процесс ждет снятия блокировки. С синхронизацией всегда связано ОЖИДАНИЕ.!

Решение: «Поочередный вход в критическую секцию»

Нить A Нить B

while (q==1); while (q==2); // Вход

КС КС // Критическая секция

q = 1; q = 2; // Выход

Что если одна нить завершится, а другая попытается войти в критическую секцию? Будет навечно заблокирован в цикле.

Решение задачи взаимного исключения ищется при следующих предположениях:

  • Процессы асинхронные

  • Только один может быть в критической секции в каждый момент времени

  • Остановка вне критической секции не мешает работать другим

  • Вход в критическую секцию гарантируется за конечное время

Программное решение задачи взаимного исключения

Решение 1:

Используем 2 флага:

q1 – нить А внутри критической секции

q2 - нить В внутри критической секции

Нить A Нить B

while (q2); while (q1); // Вход

q1=true; q2=true;

КС КС // Критическая секция

q1 = false; q2 = false; // Выход

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

Решение 2.

Используем 2 флага:

q1 – нить А внутри критической секции

q2 - нить В внутри критической секции

Нить A Нить B

q1=true; q2=true;

while (q2); while (q1); // Вход

КС КС // Критическая секция

q1 = false; q2 = false; // Выход

В этом решении изменение порядка установки флаг и проверки может привести к блокировке, если оба успели установить флаги до проверки.

Решение 3.

Используем 2 флага и постараемся избежать блокировки:

q1 – нить А внутри критической секции

q2 - нить В внутри критической секции

Нить A Нить B

q1=true; q2=true;

while (q2) { while (q1) { // Вход

q1 = false; q2 = false; // снять флаг

sleep(?); sleep(?);

q1=true; q2=true;

} }

КС КС // Критическая секция

q1 = false; q2 = false; // Выход

В этом решении практически все правильно, но теоретически можно предположить одинаковый темп работы процессов, так что возникнет бесконечное откладывание

Решение Деккера (1970).

Вводим дополнительную переменную для того, чтобы две нити вели себя по-разному:

q1 – нить А внутри критической секции

q2 - нить В внутри критической секции

Нить A Нить B

q1=true; q2=true;

while (q2) { while (q1) { // Вход

if(z==2) { if(z==1) {

q1 = false; q2 = false; // снять флаг

while(z==2); while(z==1);

q1=true; q2=true;

} }

} }

КС КС // Критическая секция

z = 2; z = 1; // Выход

q1 = false; q2 = false;

Решение Петерсена (1981)

Int lastID; // 0 , 1

Bool InSect[2];

Void Enter(int procID) { Void Leave(int procID) {

Int other = 1 - procID; InSect[procID] = false;

InSect[procID] = true; }

LastID = procID;

While(lastID==procID && InSect[other]);

}

Резюме

  • Решение слишком сложное для такой простой задачи

  • Решение не симметричное. А что, если не две задачи?

  • Пока А ждет, он занимает процессор («занятое ожидание»)

Что нужно?

  • Более сложные атомарные инструкции на аппаратном уровне

  • Высокоуровневые примитивы в языках для взаимного исключения, опирающиеся на аппаратную поддержку (lock-unlock).

  • Исключить «занятое ожидание»

Хотелось бы видеть решение примерно в таком виде:

Lock();

КС;

UnLock();

Соседние файлы в папке вар1