Rationale for Ada 2005: Tasking and Real-Time
RUSTOPBACKNEXT
ENG |
2. Task termination
@ In the Introduction we mentioned the problem of how tasks can have a silent death in Ada 95. This happens if a task raises an exception which is not handled by the task itself. Tasks may also terminate because of going abnormal as well as terminating normally. The detection of task termination and its causes can be monitored in Ada 2005 by the package Ada.Task_Termination whose specification is essentially
|
|
|
|
|
|
Rationale for Ada 2005: Tasking and Real-Time
@ENGRUSTOPBACKNEXT2. Завершение задачи
@ Во Введении мы упоминали проблему которая возникает у задач в процессе т.н. тихой смерти на Аде 95. Это случается когда в задаче возникает исключение которое не обрабатывается непосредственно задачей. Задачи могут также закончиться аварийно так же как и обычно. Обнаружение завершения задачи и его причин может быть проведено в Аде 2005 при помощи пакета Ada.Task_Termination, спецификация которого следующая:
|
@ (Отметим, что вышеупомянутое включает выражения использования чтобы упростить представление; у фактического пакета нет выражений использования. Мы будем использовать подобный подход для других предопределенных пакетов, описанных в этой статье). Основная идея состоит в том, что мы можем связать защищенную процедуру с задачей. Защищенная процедура вызывается когда задача заканчивается с индикацией причины, которая передаётся через ее параметры.
@ Защищенная процедура идентифицируется типом Termination_Handler, который является ссылочным типом обращающимся к защищенной процедуре.
@ Ассоциация может быть сделана двумя способами. Таким образом (как во Введении) мы могли бы объявить защищенный объект Grim_Reaper:
|
@ который содержит защищенную процедуру Last_Gasp. Отметим, что параметры Last_Gasp соответствуют таковым из ссылочного типа Termination_Handler.
@ Мы можем тогда назначить Last_Gasp как защищенную процедуру, которая будет вызвана, когда определенная задача T помрёт:
|
@ Альтернативно мы можем назначить Last_Gasp как защищенную процедуру, которая будет вызываться когда любая из задач, зависящих от текущей задачи завершится написав Set_Dependents_Fallback_Handler (Grim_Reaper. Last_Gasp'Access); Отметим, что задача не может установить обработчик для самой себя.
@ Таким образом, у задачи может быть два обработчика. Обработчик системы восстановления и специфический обработчик. При завершении задачи непосредственно перед тем как задача исчезает вызвается специфический обработчик, если он не пустой. В противном случае вызывается обработчик системы восстановления, если он, в свою очередь, сам не является пустым. Если оба обработчика - пустые тогда, никакой обработчик не вызвается.
@ В теле защищенной процедуры Last_Gasp можно вывести различные диагностические сообщения:
|
@ Есть три возможных варианта завершения: нормальное, аварийное (вызванное аварийным прекращением работы), и из-за распространения необработанного исключения. В последнем случае параметр X сообщает подробности вхождения исключения, тогда как в других случаях X имеет значение Null_Occurrence.
@ Первоначально и специфический и обработчик системы восстановления являются пустыми для всех задач. Однако, если обработчик системы восстановления был установлен для всех зависимых задач T тогда, обработчик будет также относиться к любой задаче впоследствии созданной T или одним из его потомков. Таким образом, задача уже может родиться уже с обработчиком системы восстановления.
@ Если устанавливается новый обработчик, тогда он заменяет любой существующий обработчик соответствующего вида. Вызов любой процедуры установки с пустым указателем для обработчика естественно делает соответствующий обработчик пустым.
@ Текущие обработчики могут быть получены вызовом функции Current_Task_Fallback_Handler или Specific_Handler; они возвращают пустой указатель, если обработчик - пустой.
@ Важно понять, что обработчики системы восстановления для задач, зависящих от T, не обязательно должны быть одинаковыми, так как любая из зависимых задач T может установить собственный обработчик для своих собственных зависимых задач.
@ Таким образом, обработчики системы восстановления для дерева задач могут быть различными в различных поддеревьях. Эта структура отражена тем фактом, что определение текущего обработчика системы восстановления задачи фактически делается рекурсивным поиском в задачах от которых он зависит.
@ Отметим, что мы не можем непосредственно опросить обработчик системы восстановления любой задачи, мы можем это сделать только для текущей задачи. Кроме того, если задача установит обработчик системы восстановления для своих потомков и затем спросит свой собственный обработчика системы восстановления, то она не получит тот же самый ответ, потому что это не один из его собственных потомков.
@ Важно понять ситуацию относительно задачной среды. Эта неназванная задача - задача, которая разрабатывает библиотечные модули и затем вызывает основную подпрограмму. Помните, что библиотечные задачи (которые являются задачами, объявленными на библиотечном уровне) активизированы задачей среды прежде, чем будет вызвана основная подпрограмма.
@ Предположим, что основная подпрограмма вызывает процедуры установки следующим образом:
|
@ Здесь специфический обработчик для задачной среды установлен Two (потому что Current_Task - задача среды в этом пункте), но обработчик системы восстановления для задачи среды - пустой. С другой стороны обработчик системы восстановления для всех других задач в программе, включая любые библиотечные задачи установлен One.
@ Отметим, что не возможно установить обработчик системы восстановления для задачи среды.
@ Проницательный читатель отметит, что при определённых обстоятельствах библиотечная задача может закончится раньше чем обработчик будет установлен. Мы можем это преодолеть установив обработчик как часть кода элаборации следующим образом:
|
@ Отметим, как использование прагм Elaborate_Body и Elaborate гарантирует, что вещи сделаны в правильном порядке.
@ Некоторые незначительные пункты - то, что, если мы пытаемся установить специфический обработчик для задачи, которая уже завершена возбуждается исключение Tasking_Error. И если мы пытаемся установить специфический обработчик для пустой задачи, которая является вызовом Set_Specific_Handler с параметром T равным Null_Task_Id, тогда возбуждается исключение Program_Error. Эти исключения также возбуждаются вызовами функции Specific_Handler при подобных обстоятельствах.
2010-10-24 00:26:55
шлагбаум, сравни цены - найди где дешевле и ближе купить. . .