Процессы называются параллельными, если они существуют одновременно. Параллельные процессы могут работать совершенно независимо
друг от друга или они могут быть асинхронными – это значит им необходимо периодически синхронизироваться и взаимодействовать. Для иллюстрации параллельных асинхронных
процессов применяется нотация аналогичная той, которая применяется
в языках параллельного программирования Модула, Ада и т. п.
Параллельная обработка
Параллельное выполнение нескольких программ заманчиво,
как один из вариантов повышения быстродействия, и как следствие – производительности
ОС. Многопроцессорные вычислительные комплексы (суперкомпьютеры)
дают основание надеяться на внедрение мультипроцессорных систем в персональные
компьютеры, и в результате – на развитие основных концепций параллельного
программирования и создание соответствующего программного обеспечения. Здесь
встречаются принципиальные трудности:
- сложность определения фрагментов будущих программ, возможных
быть
распараллеленными;
- трудность отладки таких программ. Т.к. после предположительного
исправления ошибки трудно восстановить последовательность событий,
на которых эта ошибка проявилась впервые. Поэтому нельзя утверждать с
уверенностью, что данная ошибка устранена.
- трудность доказательства корректности параллельных программ
по сравнению с последовательными программами.
Взаимоисключение
Пусть имеется многотерминальная система разделения времени,
в которой пользователи вводят текстовые данные. Каждый пользователь
использует один терминал. Ввод очередной строки заканчивается нажатие на клавишу
Enter. Необходимо вести постоянный учет общего количества строк, введенных пользователями
с начала работы системы. Предполагается, что контроль каждого терминала
ведется при помощи отдельного процесса. Сигналом к увеличению на 1 глобальной
переменной STROKWWEDENYH – служит ввод сигнала Enter с соответствующего
терминала. Пусть каждый процесс имеет в своем составе копию кода:
mov ax, STROKWWEDENYH
inc ax
mov STROKWWEDENYH, ax
Пусть в данный момент глобальная переменная
STROKWWEDENYH имеет значение 21687. Пусть один процесс успевает выполнить только
первые две команды mov ax, STROKWWEDENYH inc ax
После чего в регистре ax (аккумуляторе) будет 21688. Затем
этот процесс ввиду истечения отведенного ему кванта времени уступает процессор
другому процессу. Второй процесс выполняет теперь все три команды, устанавливая
значение
STROKWWEDENYH=21688. Далее 2-й процесс возвращает управление
1-ому процессу, который возобновляет свое выполнение с команды mov STROKWWEDENYH, ax и также помещает значение 21688 в STROKWWEDENYH. Т.о.,
из-за не координированного доступа к разделяемой переменной
STROKWWEDENYH – потеряли одну строку.
Эту задачу можно решить, если каждому процессу предоставить
монопольное исключительное право доступа к переменной
STROKWWEDENYH. Когда один процесс увеличивает эту разделяемую переменную, всем остальным
процессам, которым нужно было бы также, нарастить значение STROKWWEDENYH в то же
самое время – придется ждать. А когда данный процесс закончит свое использование
переменной, будет разрешено продолжать работу одному из процессов, находящихся
в состоянии ожидания. Т. о. каждый процесс, обращающийся к разделяемым данным,
исключает
для других процессов возможность одновременного с ним обращения к
данным. Это называется взаимоисключением. Когда процесс производит обращение
к разделяемым данным, то говорят, что он находится на своем критическом участке.
Применение примитивов взаимоисключения
для управления взимодействием процессами
program взаимоисключение;
var строквведенных: целое;
procedure
процессодин;
while истина do
begin
взятиеследующейстрокитерминала;
входвзаимоисключения;
строквведенных:=строквведенных + 1;
выходвзаимоисключения;
обработкастроки
end;
procedure процессдва;
while истина do
begin
взятиеследующейстрокитерминала;
входвзаимоисключения;
строквведенных:=строквведенных + 1;
выходвзаимоисключения;
обработкастроки
end;
begin
строквведенных:=0;
parbegin
процессодин;
процессдва
parend
end.
Для простоты полагаем, что взаимодействуют два параллельных
процесса. Управлять n процессами – значительно сложнее. Две конструкции входвзаимоисключения и выходвзаимоисключения обрамляют критические участки в каждом из процессов. Эти операторы
называются примитивы взаимоисключения. Внутри этого участка обеспечен монопольный
доступ к переменной
СТРОКВВЕДЕННЫХ.
Если один из процессов находится внутри своего критического
участка, а другой процесс пытается войти в этот же участок, то он переводится
в состояние ожидания, пока первый процесс не выполнит выходвзаимоисключения. Только после этого первый процесс сможет войти в свой критический участок.
Операторные скобки parbegin
оператор 1;
оператор 2;
…………..
оператор n
parend
служат для синтаксического оформления параллельно выполняющихся
процессов в рамках программы, где они употреблены. Оператор parbegin указывает, что последовательное течение программы должно быть разделено на несколько параллельно выполняемых последовательностей
(цепочек управления). В данном случае на n отдельных самостоятельных цепочек - по
одной для каждого внутреннего оператора для данной конструкции.
Оператор parend указывает, что вышеперечисленные параллельно выполняемые цепочки должны слиться воедино и должно возобновиться последовательное
выполнение программы.
Если процессодин и процессдва выполняют входвзаимоисключения одновременно, то одному из них случайным образом будет разрешено продолжать
работу, а другому – остается ждать.
Реализация примитивов взаимоисключения
(общие замечания).
Для реализации примитивов взаимоисключения «входвзаимоисключения»
(код входа взаимоисключения) и «выходвзаимоисключения» (код
выхода взаимоисключения) необходимо, чтобы соблюдались следующие четыре правила:
1. Задача д. б. решена чисто программным способом на ЭВМ
(компьютере), не имеющей специальных команд взаимоисключения. Каждая команда машинного языка выполняется, как неделимая операция, т. е. каждая ______8начатая команда завершается без прерывания ее. Будем считать, что в случае одновременных попыток нескольких процессоров обратиться
к одному и тому же элементу данных возможные конфликты разрешаются
аппаратно при помощи схемы защитной блокировки памяти. Эта схема распараллеливает конфликтующие обращения к памяти со стороны отдельных процессоров, выстраивая их в очередь, т. е.,
разрешая производить только одно обращение в каждый конкретный момент
времени. Предполагается, что эти отдельные обращения обслуживаются
в случайном порядке.
2. Не должно быть никаких предположений об относительных
скоростях выполнения асинхронных параллельных процессов.
3. Процессы, находящиеся вне своих критических участков,
не могут препятствовать другим процессам входить в их собственные
критические участки.
4. Не должно быть бесконечного откладывания момента входа
процессов в их критические участки. Неплохие реализации программных механизмов взаимоисключения
предложил голландский математик Деккер. Существенно улучшил этот
алгоритм Э. Дейкстра.
|