Способы вызова модулей
Программный модуль можно инициировать разными способами, причем почти все из них связаны с определенным типом модуля.
Широко используемым типом модулей является подпрограмма. С подпрограммой, или вызываемой процедурой, некоторым несимметричным образом связывается вызывающий блок. Исполнение начинается после того, как вызывающий блок специальным образом укажет вызываемую процедуру, по завершении которой управление возвращается обратно в этот блок. Запись активации для вызываемой процедуры создается при обращении к ней, она записывается в стек выше записи активации вызывающего блока и уничтожается после окончания. При межмодульном взаимодействии можно передавать параметры от вызывающего модуля к вызываемому модулю. Действия, обеспечивающие вызов подпрограммы, передачу параметров и возврат управления, называются связыванием подпрограмм.
Функция прерывания также вызывается несимметрично, либо явно, либо, что чаще, в ответ на возникновение во время исполнения вызывающего блока некоторой оговоренной интуиции. Такие функции не имеют параметров. Основной трудностью, возникающей при программировании с использованием функций прерывания, является сложность включающих их программ. Существенные трудности могут возникать также при их трансляции.
В отличие от подпрограммы, которая подчинена тому, кто ее вызвал, сопрограмма - это модуль, не подчиненный другим модулям. В то время как вызов подпрограммы создает запись активации этой подпрограммы, а возврат управления из нее уничтожает эту запись, возобновление сопрограммы ни создает, ни уничтожает запись активации. Исполнение сопрограммы - это просто возобновление ее действий с того места, где она последний раз остановилась, а не с фиксированной точки. Поэтому ее запись активации должна хранить текущую точку для следующего возобновления, и тем самым вызов сопрограммы выглядит симметрично. На рис. 2.24 приведены примеры вызова сопрограммы и подпрограммы.
Запись активации сопрограммы создается при ее первом вызове, который отличается от возобновления. Этот первоначальный вызов можно назвать выделением, поскольку он выделяет запись активации. Уничтожение записи активации может произойти либо автоматически, когда сопрограмма выполнит последнюю команду, либо явно, в результате выполнения команды освобождения, выданной другим модулем, обычно тем, который инициировал создание записи активации.
Сопрограмме, так же как и подпрограмме, можно передавать параметры, однако передачу можно осуществлять много раз: при первоначальном вызове, при первом возобновлении, которое следует за ним, и даже при каждом возобновлении.
Существует еще один способ инициации подпрограмм или сопрограмм, при котором каждая из них рассматривается как отдельный процесс. Вместо выполнения команд вызова, возврата и возобновления осуществляется обращение к диспетчеру с требованием выполнить соответствующие действия. Использование этой управляющей программы для задания последовательности исполнения может повысить эффективность использования ресурсов. Процессы, вызываемые таким способом, были названы событиями, а информация для каждого процесса, чье исполнение было запрошено, - уведомлением о событии. Всякий раз, когда исполнение одного модуля прекращается, управление передается диспетчеру, который анализирует уведомления и выбирает один модуль для исполнения. Чтобы избавиться от просмотpa всех уведомлений, можно хранить уведомления о событиях в очереди событий, упорядоченной в соответствии с некоторым критерием, таким, например, как время исполнения или диспетчерский приоритет. Очереди событий предназначены для глобального управления инициированием модулей.
События исполняются последовательно в результате запланированных вызовов. Если же процессы работают действительно параллельно, а не просто чередуются, то можно использовать способ инициирования - незапланированное следование. При этом один модуль может вызвать другой, и тот будет исполняться параллельно с первым. Такой способ инициирования часто называют разветвлением. В этой ситуации последовательность исполнения различных модулей не зависит от того, когда какой был вызван. Если для сопрограмм последовательность исполнения определяется возобновлениями, то для событий - диспетчером. Такая неопределенность последовательности исполнения порождает уже рассмотренные ранее проблемы синхронизации.