Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 700363.doc
Скачиваний:
16
Добавлен:
01.05.2022
Размер:
3.69 Mб
Скачать

Алгоритмы взаимоисключения с активным ожиданием

Наиболее простым решением для разработки алгоритмов взаимоисключения представляется использование цикла ожидания перед входом в критическую секцию, когда процесс, ожидающий освобождение критической секции, непрерывно выполняет циклическую проверку условия перед входом в нее. Такой подход обычно называется spin-блокировкой, от английского слова spin – вращение.

Рассмотрим последовательно несколько таких алгоритмов. Отметим сразу, что не все из них удовлетворяют требованиям к алгоритмам взаимоисключения, приведенным в предыдущем разделе. Но эти алгоритмы хорошо иллюстрируют сложность проблемы и множество узких мест, возникающих при реализации механизма взаимоисключений.

Алгоритм 1

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

// глобальный флаг для защиты критической секции extern bool flag = false; … … … … … // цикл ожидания освобождения критической секции while(flag); // захват критической секции flag = true; // код критической секции flag = false; // освобождение критической секции

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

вр. к-та

действия процесса №1

действия процесса №2

1

while(flag);

2

while(flag); flag = true // код критической секции

3

flag = true // код критической секции

Проблема состоит в том, что момент переключение процессов

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

Алгоритм 2

Рассмотрим еще один вариант алгоритма взаимоисключений для двух процессов.

// подготовка extern int num = 1; // номер процесса, // которому разрешено войти // в критическую секцию

// процесс 1 // цикл ожидания while(num != 1); // код критической // секции // разрешено работать // процессу 2 num = 2;

// процесс 2 // цикл ожидания while(num != 2); // код критической // секции // разрешено работать // процессу 1 num = 1;

В качестве примера, показан алгоритм для двух процессов, но он может быть легко адаптирован для работы также и с произвольным числом процессов. Цикл ожидания каждого конкретного процесса продолжается до тех пор, пока он не получит право работать дальше, т.е. пока значение параметра num не станет равным номеру данного процесса. Завершая свой критический участок, процесс указывает номер следующего процесса, которому будет разрешено войти в критическую секцию, и т.д.

Легко показать, что данный подход действительно обеспечивает взаимоисключение, но он имеет существенный недостаток – процессы должны входить в свои критические секции в строго определенном порядке. Это очень существенный недостаток, если процессы имеют различную периодичность входа в критическую секцию. Например, если первый процесс должен входить в критическую секцию каждую миллисекунду, а второй процесс – каждую секунду. При использовании же показанного алгоритма, процессы не могут заходить в критическую секцию два раза подряд, следовательно, первый процесс должен будет ждать, пока второй процесс не пройдет через критическую секцию, что очень замедлит работу первого процесса.

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