Если алгоритм требует запоминания и переименования задачи, то это можно сделать определением ссылочного типа, указывающего на соответствующие заданные объекты, и использованием ссылочных значений для целей идентификации (см. предыдущий пример). Присваивание для такого ссылочного типа возможно, как и для любого другого ссылочного типа.
Для заданных типов допустимы описания подтипов, как и для других типов, но никакие ограничения к заданному типу не применимы.
Выполнение и активизация задачи
Тело задачи определяет выполнение всякой задачи, которая указывается заданным объектом соответствующего задачного типа. Начальный этап этого выполнения называется активизацией заданного объекта и указанной им задачи; активизация состоит из предвыполнения раздела описаний (если он есть) тела задачи. Выполнение различных задач, в частности, их активизация, производится параллельно.
Если задачный объект описан непосредственно в разделе описаний, то активизация задачного объекта начинается после предвыполнения раздела описаний, предшествующего зарезервированному слову begin; аналогично, если такое описание помещено непосредственно в спецификацию пакета, то активизация начинается после предвыполнения раздела описаний тела пакета. То же относится и к активизации задачного объекта, являющегося подкомпонентом объекта, описанного непосредственно в разделе описаний или спецификации пакета. Первый оператор, следующий за разделом описаний, выполняется только после окончания активизации заданных объектов.
Если при активизации одной из таких задач возбуждается исключение, то эта задача становится законченной (см. 9.4); на других задачах это прямо не отражается. Если во время своей активизации одна из этих задач становится законченной, то после завершения (успешного или нет) активизации всех задач возбуждается исключение TASKING_ERROR; исключение возбуждается непосредственно за разделом описаний перед выполнением первого оператора (непосредственно после зарезервированного слова begin ). Исключение TASKING_ERROR возбуждается лишь однажды, даже если во время активизации сразу несколько задач становятся законченными таким способом.
Если исключение возбуждается при предвыполнении раздела описаний или спецификации пакета, то любая созданная (прямо или косвенно) этим предвыполнением задача, которая еще не активизирована, становится завершенной, и, таким образом, она никогда не активизируется (см. разд. 9.4 с определением завершенной задачи).
Приведенные выше правила предполагают, что в теле пакета без операторов присутствует пустой оператор. Для пакета без тела подразумевается тело пакета с единственным пустым оператором. Если пакет без тела описывается непосредственно в некотором программном модуле или в операторе блока, то его тело подразумевается в конце раздела описаний программного модуля или оператора блока; при наличии нескольких пакетов без тела порядок следования подразумеваемых тел пакетов неопределен.
Задачный объект, являющийся объектом или подкомпонентом объекта, созданного выполнением генератора, активизируется этим выполнением. Активизация начинается после инициализации объекта, созданного генератором; если несколько подкомпонентов являются заданными объектами, они активизируются параллельно. Ссылочное значение, указывающее этот объект, возвращается генератором только после проведения этих активизаций.
Если исключение возбуждается при активизации одной из таких задач, то она становится законченной задачей; на другие задачи этот факт не оказывает прямого воздействия. Если во время своей активизации одна из этих задач становится законченной таким образом, то после проведения (успешного или нет) активизации всех этих задач возбуждается исключение TASKING_ERROR; исключение возбуждается в той точке программы, где выполняется генератор. Исключение TASKING_ERROR возбуждается лишь однажды, даже если во время активизации сразу несколько задач становятся законченными таким образом.
Если исключение возбуждается во время инициализации объекта, созданного генератором (следовательно, до начала активизации), то любая задача, указанная подкомпонентом этого объекта, становится завершенной, и, таким образом, она никогда не активизируется.
Пример:
procedure Р is
А, В: РЕСУРС; - - предвыполняет заданные объекты А и В
С: РЕСУРС; - - предвыполняет заданный объект С
begin
- задачи А, В, С активизируются параллельно
- перед выполнением первого оператора
end;
Примечание. Вход задачи может быть вызван до активизации задачи. Если несколько задач активизируются параллельно, выполнение любой из них не предполагает ожидания конца активизации других задач. Задача может стать законченной во время ее активизации как из-за исключения, так и из-за прекращения (см. 9.10).
Зависимость и завершение задач
Каждая задача зависит по крайней мере от одного родителя. Родитель - это конструкция, являющаяся либо задачей, либо в данный момент выполняемым оператором блока или подпрограммой, либо библиотечным пакетом (но не описанным в другом программном модуле). Зависимость от родителя является непосредственной зависимостью в следующих двух случаях:
Задача, указанная заданным объектом, который является объектом или подкомпонентом объекта, созданными при выполнении генератора, зависит от родителя, предвыполняющего соответствующее описание ссылочного типа.
Задача, указанная другим заданным объектом, зависит от родителя, выполнение которого создает заданный объект.
Более того, если задача зависит от данного родителя, являющегося оператором блока, выполняемым Другим родителем, то задача также косвенно зависит и от этого родителя; то же справедливо, если данный родитель является подпрограммой, вызванной другим ррдителем, а также если данный родитель — задача, зависящая (прямо или косвенно) от другого родителя. Зависимости существуют и для объектов личного типа, полное описание которого задано в терминах заданного типа.
Говорят, что задача закончила свое выполнение, когда осуществилось выполнение последовательности операторов, помещенных в ее теле за резервированным словом begin. Аналогично этому, блок или подпрограмма закончили свое выполнение, когда осуществилось выполнение соответствующей последовательности операторов. В случае оператора блока также говорят, что выполнение его закончилось при достижении операторов выхода, возврата или перехода, передающих управление из блока. В случае процедуры также говорят, что ее выполнение закончилось при достижении соответствующего оператора возврата. В случае функции также говорят, что ее выполнение закончилось после вычисления результирующего выражения в операторе возврата. Наконец, выполнение задачи, оператора блока или подпрограммы закончено, если при выполнении содержащихся в них соответствующих последовательностей операторов возбуждено исключение и нет соответствующего ему обработчика, а при его наличии — по окончании выполнения соответствующего обработчика.
Если у задачи нет зависимых задач и закончено ее выполнение, имеет место ее завершение. После завершения говорят, что она завершена. Если задача имеет зависимые задачи, то ее завершение имеет место после окончания выполнения задачи и завершения всех зависимых задач. Из оператора блока или тела подпрограммы, чье выполнение закончено, нельзя выйти до завершения всех зависимых задач.
С другой стороны, завершение задачи имеет место тогда и только тогда, когда ее выполнение достигло открытой альтернативы завершения в операторе отбора (см. 9.7.1) и удовлетворены Следующие условия:
Задача зависит от некоторого родителя, выполнение которого закончено (следовательно, не от библиотечного пакета).
Каждая задача, зависящая от рассмотренного родителя, либо уже завершена, либо также ожидает открытой альтернативы завершения в операторе отбора.
Когда оба условия удовлетворены, задача становится завершенной вместе со всеми задачами, зависящими от этого же родителя.
Пример:
declare
type ГЛОБАЛЬНЫЙ is access РЕСУРС; - - см. 9.1
А, В: РЕСУРС;
Г: ГЛОБАЛЬНЫЙ;
begin
- - активизация А и В declare
type ЛОКАЛЬНЫЙ is access РЕСУРС;
X: ГЛОБАЛЬНЫЙ: = new РЕСУРС; - - активизация X. all
Л: ЛОКАЛЬНЫЙ: = new РЕСУРС; - - активизация Л. all
С: РЕСУРС;
begin
- - активизация С
Г: = X; - - Г и X указывают один и тот же заданный объект
end; - - ожидание завершения С и Л. all, но не X. all
end; - - ожидание завершения А, В и Г. all
Примечание. Правила завершения подразумевают, что все задачи, зависящие (прямо или косвенно) от данного родителя и еще не завершенные, могут завершиться (коллективно) тогда и только тогда, когда каждая из них ожидает открытой альтернативы завершения в операторе отбора, и выполнение данного родителя закончено.
Те же правила справедливы и для главной программы. Следовательно, для завершения главной программы необходимо завершение всех зависимых задач, даже если соответствующий заданный тип описан в библиотечном пакете. С другой стороны, завершение главной программы не зависит от завершения задач, в свою очередь зависящих от библиотечных пакетов; в языке не определено, требуется ли завершение таких задач.
Для ссылочного типа, являющегося производным другого ссылочного типа, соответствующее определение ссылочного типа является определением родительского типа; зависимость в данном случае является зависимостью от родителя, который пред- выполняет основные определения родительского ссылочного типа.
Описание переименования вводит новое имя для уже существующего понятия, и, следовательно, не порождает дальнейшей зависимости.
Входы, вызовы входов и операторы принятия
Вызовы входов и операторы принятия являются основными средствами синхронизации задач и передачи значений между задачами. Описание входа подобно описанию подпрограммы и допустимо только в спецификации задачи. Действия, которые следует выполнить после вызова входа, задаются соответствующими операторами принятия.
описание_входа : : =
entry идентификатор [ (дискретный диапазон) ] [раздел_формальных_параметров]
оператор_вызова_входа : : =
имя_входа [раздел_фактических_параметров];
оператор_принятия : : =
accept простое_имя_входд [ (индекс_входа) ] [раздел_формальных_параметров] [do последовательность_операторов
end [простое_имя_входа] ] ;
индекс_входа : : = выражение
Описание входа, включающее дискретный диапазон (см. разд. 3.6.1), описывает семейство различных входов с одним и тем же разделом формальных параметров (если он есть), а именно по одному входу для каждого значения дискретного диапазона. Термин одиночный вход используется при определении правил, применимых к любому входу, отличному от члена семейства. Задача, указанная объектом задачного типа, имеет вход (входы), который (которые) описан (описаны) в спецификации этого задачного типа.
В теле задачи каждый из ее одиночных входов или семейства входов может быть именован соответствующим простым именем. Имя входа семейства записывается в форме индексируемого компонента: за простым именем семейства в круглых скобках следует индекс; тип этого индекса должен быть тем же, что и тип дискретного диапазона в соответствующем описании семейства входов. Вне тела задачи имя входа записывается в форме именованного компонента, префикс которого обозначает задачный объект, а постфикс является простым именем ОДНОГО из одиночных входов или семейства входов.
Одиночный вход совмещается с подпрограммой, литералом перечисления или другим одиночным входом, если у них одинаковые идентификаторы. Совмещение для семейств входов не определено. Одиночный вход или вход семейства могут быть переименованы в процедуру, как поясняется в разд. 8.5.
Виды параметров, определенные для параметров формального раздела описания входа, такие же, как в описании подпрограммы, и имеют тот же смысл (см. 6.2). Синтаксически оператор вызова входа подобен оператору вызова процедуры; правила сопоставления параметров остаются теми же, что и для вызовов подпрограмм (см. 6.4.1 и 6.4.2).
Оператор принятия задает действия, которые выполняются при вызове упомянутого в этом операторе входа (им может быть и вход семейства). Раздел формальных параметров оператора принятия должен быть согласован с разделом формальных параметров, заданным в описании одиночного входа или семейства входов, упомянутых в операторе принятия (см. разд. 6.3.1 о согласовании). Если в конце оператора принятия используется простое имя, оно должно повторять простое имя, заданное в начале этого оператора.
Оператор принятия входа данной задачи допускается только в соответствующем теле задачи, исключая тело программного модуля, вложенного в тело задачи, и другой оператор принятия этого же одиночного входа или входа того же семейства. (Из этих правил следует, что задача может выполнять операторы принятия только своих входов). Тело задачи может содержать несколько операторов принятия одного и того же входа.
При предвыполнении описания входа вначале вычисляется дискретный диапазон (если он есть), затем также, как в описании подпрограммы, пред- выполняется раздел формальных параметров (если он есть).
Выполнение оператора принятия начинается с вычисления индекса входа (в случае входа семейства) . Выполнение оператора вызова входа начинается с вычисления имени входа, затем следуют вычисления, требуемые для фактических параметров, как и при вызове подпрограммы (см. 6.4). Дальнейшее выполнение оператора принятия и соответствующего оператора вызова входа синхронизировано.
Если данный вход вызывается только одной задачей, то предоставляются две возможности: