Возврат на сайт | Назад | Оглавление | Вперед |
Во вводной части этого раздела мы остановимся на логической задаче, которая возникает при взаимодействии различных процессов, когда они должны делить одни и те же ресурсы. Эта проблема выбрана по разным причинам. Во-первых, она является непосредственным обобщением известной ситуации, согласно которой два человека не могут воспользоваться одновременно одной секцией вращающейся двери. Во-вторых, решение этой проблемы, которое я считаю нетривиальным и которое будет приведено в ╖6.1, дает нам хороший пример более тонких правил взаимодействия, чем те, с которыми мы до сих пор встречались. В-третьих, она предоставляет нам возможность проиллюстрировать (в ╖6.2) методы программирования, с помощью которых может быть достигнут дальнейший прогресс в наглядности представления. Для начала я приведу один пример разделения ресурсов. В качестве "процессов" мы можем принять "программы", описывающие некоторый вычислительный процесс, выполняемый вычислительной машиной. Выполнение такого вычислительного процесса требует определенного времени, в течение которого в памяти вычислительной машины хранится информация. Ограничимся процессами, о которых заранее известно следующее:
Предполагаем, что имеющаяся память поделена на "страницы" фиксированного размера, которые с точки зрения программы считаются эквивалентными.
Фактическое требование нужного процессу объема памяти может быть функцией, изменяющейся по мере протекания процесса, но, конечно, в соответствии с заранее заданной верхней границей. Предположим, что отдельные процессы запрашивают и возвращают память единицами в одну страницу. "Эквивалентность" (см. последнее слово предыдущего абзаца) означает, что процесс, запрашивающий новую страницу, просит просто "новую страницу", но никогда не специальную страницу или страницу из специальной группы.
Теперь мы потребуем, чтобы процесс, однажды начатый, получил рано или поздно возможность завершить свои действия, и будем отбрасывать любую схему, при которой может случиться, что процесс уничтожается на полдороге из-за своих действий, тем самым напрасно растратив уже выделенное ему на вычисления время.
Если вычислительная машина выполняет процессы один за другим, то они должны удовлетворять единственному условию, чтобы максимально требуемый ими объем памяти не превышал общую емкость памяти машины.
Если, однако, вычислительная машина обслуживает одновременно более одного процесса, то можно придерживаться правила, что допускаются только такие программы, у которых сумма их максимальных требований не превышает общей емкости памяти. Это правило, хотя и обеспечивает безопасность, является излишне ограничивающим, так как предполагает, что каждый процесс действительно занимает максимальную память во все время выполнения. Если мы посмотрим на следующую таблицу (где процессы "заимствуют" страницы из имеющейся памяти)
Процесс | Максимальное требование |
Настоящий объем |
Дальнейшее требование |
П1 П2 |
80 60 |
40 + 20 |
40 40 |
Свободная память = 100 - 60 = 40 |
(предполагается, что вся память составляет 100 страниц), то увидим, что в этой ситуации еще нет ничего страшного.
Если бы, однако, оба процесса затребовали теперь по следующей странице, и получили бы ее, то сложилась бы такая ситуация:
Процесс | Максимальное требование |
Настоящий объем |
Дальнейшее требование |
П1 П2 |
80 60 |
41 + 21 |
39 39 |
Свободная память = 100 - 62 = 38 |
Эта ситуация опасная, так как оба процесса могут пожелать полностью
затребовать свой допустимый объем памяти, не возвращая ни одной страницы. Так,
каждый из них может нуждаться в следующих 39 страницах, в то время как их
осталось только 38.
Эта ситуация, когда один из процессов может быть продолжен только при
условии, что другой будет сперва уничтожен, называется "Смертельное Объятие"
("The Deadly Embrace")10).
Проблема, которую нам необходимо решить, заключается в следующем: как избежать
опасности тупика, не накладывая слишком больших ограничений.
Банкир обладает конечным капиталом во флоринах. Он решает принимать клиентов,
которые могут занимать у него флорины на следующих условиях:
Основными вопросами здесь являются: Ответ на вопрос (а) прост: он может принять любого клиента, чья максимальная
потребность не превышает капитал банкира.
Для ответа на вопрос (б) введем следующую терминологию.
Банкир имеет в своем распоряжении фиксированный "капитал";
каждый новый клиент устанавливает свою максимальную "потребность" и
для любого клиента выполняется условие: Текущая обстановка для каждого клиента характеризуется его
"заемом". Каждый заем первоначально равен "0" и будет в любой
момент удовлетворять соотношению: Отсюда может быть получена полезная величина, представляющая максимальное
дальнейшее "требование": Наконец, "наличные" банкира составляют: Очевидно, что должно выполняться условие: Для того чтобы решить, выплачивать ли запрашиваемый флорин клиенту, банкир по
существу оценивает положение, которое сложилось бы, если бы он произвел выплату.
Если это положение "безопасно", он выплачивает флорин; если положение не
"безопасно", он должен сказать: "Извиняюсь, но вы должны подождать".
Проверка того, является ли положение безопасным, равнозначна проверке, могут
ли быть с гарантией завершены все сделки. Алгоритм начинается с исследования,
имеет ли по крайней мере один клиент "требование", не превосходящее
"наличные". Если так, то этот клиент сможет завершить свою сделку,
и поэтому исследуются оставшиеся клиенты в предположении, что первый завершил
сделку и возвратил свой заем полностью. Безопасность положения означает, что
могут быть закончены все сделки, т.е. банкир видит путь получения обратно всех
своих денег.
Если клиенты пронумерованы от 1 до N, то
стандартную программу проверки положения можно составить так: 6.1. Алгоритм банкира
а) при каких
условиях банкир может заключить контракт с новым
клиентом?
б) при каких условиях банкир может
выплатить (следующий) запрашиваемый флорин клиенту, не опасаясь попасть в тупик?
"потребность[i] < капитал" (для всех i).
"0 < заем[i] < потребность[i]" (для всех i).
"требование[i] = потребность[i] - заем[i]" (для всех i).
"наличные = капитал - сумма всех займов".
"0 < наличные < капитал".
integer свободные деньги; Boolean безопасно;
Boolean array завершение под сомнением[1 : N];
свободные деньги := наличные;
for i := 1 step 1 until N do завершение под сомнением[i] := true;
L: for i := 1 step 1 until N do
begin if завершение под сомнением[i] and требование[i]
свободные деньги then
begin завершение под сомнением[i] := false;
свободные деньги := свободные деньги + заем[i];
goto L
end
end;
if свободные деньги = капитал
then безопасно := true
else безопасно := false
Возврат на сайт | Назад | Оглавление | Вперед |