Rationale for Ada 2005: Tasking and Real-Time

RUSTOP
BACKNEXT

ENG

5. Scheduling and dispatching

@ Another area of increased flexibility in Ada 2005 is that of task dispatching policies. In Ada 95, the only predefined policy is FIFO_Within_Priorities although other policies are permitted. Ada 2005 provides further pragmas, policies and packages which facilitate many different mechanisms such as non-preemption within priorities, the familiar Round Robin using timeslicing, and the more recently acclaimed Earliest Deadline First (EDF) policy. Moreover it is possible to mix different policies according to priority level within a partition.

@ In order to accommodate these many changes, Section D.2 (Priority Scheduling) of the Reference Manual has been reorganized as follows

@ Overall control is provided by two pragmas. They are

  1        pragma Task_Dispatching_Policy (policy_identifier);
  2        pragma Priority_Specific_Dispatching (policy_identifer, first_priority_expression, last_priority_expression);

@ The pragma Task_Dispatching_Policy, which already exists in Ada 95, applies the same policy throughout a whole partition. The pragma Priority_Specific_Dispatching, which is new in Ada 2005, can be used to set different policies for different ranges of priority levels.

@ The full set of predefined policies in Ada 2005 is FIFO_Within_Priorities – This already exists in Ada 95. Within each priority level to which it applies tasks are dealt with on a first-in-first-out basis. Moreover, a task may preempt a task of a lower priority.

@ Non_Preemptive_FIFO_Within_Priorities – This is new in Ada 2005. Within each priority level to which it applies tasks run to completion or until they are blocked or execute a delay statement.

@ A task cannot be preempted by one of higher priority. This sort of policy is widely used in high integrity applications.

@ Round_Robin_Within_Priorities – This is new in Ada 2005. Within each priority level to which it applies tasks are timesliced with an interval that can be specified. This is a very traditional policy widely used since the earliest days of concurrent programming.

@ EDF_Across_Priorities – This is new in Ada 2005. This provides Earliest Deadline First dispatching. The general idea is that within a range of priority levels, each task has a deadline and that with the earliest deadline is processed. This is a fashionable new policy and has mathematically provable advantages with respect to efficiency.

@ For further details of these policies consult the forthcoming book by Alan Burns and Andy Wellings [4].

@ These various policies are controlled by the package Ada.Dispatching plus two child packages. The root package has specification

  1        package Ada.Dispatching is
  2                pragma Pure(Dispatching);
  3                Dispatching_Policy_Error: exception;
  4        end Ada.Dispatching;

@ As can be seen this root package simply declares the exception Dispatching_Policy_Error which is used by the child packages.

@ The child package Round_Robin enables the setting of the time quanta for time slicing within one or more priority levels. Its specification is

  1        with System; use System;
  2        with Ada.Real_Time; use Ada.Real_Time;
  3        package Ada.Dispatching.Round_Robin is
  4                Default_Quantum : constant Time_Span := implementation-defined;
  5                procedure Set_Quantum (Pri : in Priority, Quantum : in Time_Span);
  6                procedure Set_Quantum (Low, High : in Priority; Quantum : in Time_Span);
  7                function Actual_Quantum (Pri : Priority) return Time_Span;
  8                function Is_Round_Robin (Pri : Priority) return Boolean;
  9        end Ada.Dispatching.Round_Robin;

@ The procedures Set_Quantum enable the time quantum to be used for time slicing to be set for one or a range of priority levels. The default value is of course the constant Default_Quantum. The function Actual_Quantum enables us to find out the current value of the quantum being used for a particular priority level. Its identifier reflects the fact that the implementation may not be able to apply the exact actual value given in a call of Set_Quantum. The function Is_Round_Robin enables us to check whether the round robin policy has been applied to the given priority level. If we attempt to do something stupid such as set the quantum for a priority level to which the round robin policy does not apply then the exception Dispatching_Policy_Error is raised.

@ The other new policy concerns deadlines and is controlled by a new pragma Relative_Deadline and the child package Dispatching.EDF. The syntax of the pragma is pragma Relative_Deadline(relative_deadline_expression); The deadline of a task is a property similar to priority and both are used for scheduling. Every task has a priority of type Integer and every task has a deadline of type Ada.Real_Time.Time. Priorities can be set when a task is created by pragma Priority

  1        task T is
  2                pragma Priority (P);

@ and deadlines can similarly be set by the pragma Relative_Deadline thus

  1        task T is
  2                pragma Relative_Deadline (RD);

@ The expression RD has type Ada.Real_Time.Time_Span. Note carefully that the pragma sets the relative and not the absolute deadline. The initial absolute deadline of the task is Ada.Real_Time.Clock + RD where the call of Clock is made between task creation and the start of its activation.

@ Both pragmas Priority and Relative_Deadline can appear in the main subprogram and they then apply to the environment task. If they appear in any other subprogram then they are ignored. Both properties can also be set via a discriminant. In the case of priorities we can write

  1        task type TT (P : Priority) is
  2                pragma Priority (P);
  3                ...
  4        end;
  5        High_Task : TT (13);
  6        Low_Task  : TT (7);

@ We cannot do the direct equivalent for deadlines because Time_Span is private and so not discrete.

@ We have to use an access discriminant thus

  1        task type TT (RD : access Timespan) is
  2                pragma Relative_Deadline (RD.all);
  3                ...
  4        end;
  5        One_Sec   : aliased constant Time_Span := Seconds (1);
  6        Ten_Mins  : aliased constant Time_Span := Minutes (10);
  7        Hot_Task  : TT (One_Sec'Access);
  8        Cool_Task : TT (Ten_Mins'Access);

@ Note incidentally that functions Seconds and Minutes have been added to the package Ada.Real_Time. Existing functions Nanoseconds, Microseconds and Milliseconds in Ada 95 enable the convenient specification of short real time intervals (values of type Time_Span). However, the specification of longer intervals such as four minutes meant writing something like Milliseconds(240_000) or perhaps 4*60*Milliseconds(1000). In view of the fact that EDF scheduling and timers (see Section 6) would be likely to require longer times the functions Seconds and Minutes are added in Ada 2005. There is no function Hours because the range of time spans is only guaranteed to be 3600 seconds anyway.

@ If a task is created and it does not have a pragma Priority then its initial priority is that of the task that created it. If a task does not have a pragma Relative_Deadline then its initial absolute deadline is the constant Default_Deadline in the package Ada.Dispatching.EDF; this constant has the value Ada.Real_Time.Time_Last (effectively the end of the universe).

@ Priorities can be dynamically manipulated by the subprograms in the package Ada.Dynamic_Priorities and deadlines can similarly be manipulated by the subprograms in the package Ada.Dispatching.EDF whose specification is

  1        with Ada.Real_Time; use Ada.Real_Time;
  2        with Ada.Task_Identification; use Ada.Task_Identification;
  3        package Ada.Dispatching.EDF is
  4                subtype Deadline is Ada.Real_Time.Time;
  5                Default_Deadline : constant Deadline := Time_Last;
  6                procedure Set_Deadline
  7                        (D : in Deadline; T : in Task_Id := Current_Task);
  8                procedure Delay_Until_And_Set_Deadline
  9                        (Delay_Until_Time : in Time; Deadline_Offset : in Time_Span);
 10                function Get_Deadline (T : Task_Id := Current_Task) return Deadline;
 11        end Ada.Dispatching.EDF;

@ The subtype Deadline is just declared as a handy abbreviation. The constant Default_Deadline is set to the end of the universe as already mentioned. The procedure Set_Deadline sets the deadline of the task concerned to the value of the parameter D. The long-winded Delay_Until_And_Set_Deadline delays the task concerned until the value of Delay_Until_Time and sets its deadline to be the interval Deadline_Offset from that time – this is useful for periodic tasks. The function Get_Deadline enables us to find the current deadline of a task.

@ It is important to note that this package can be used to set and retrieve deadlines for tasks whether or not they are subject to EDF dispatching. We could for example use an ATC on a deadline overrun (ACT = Asynchronous Transfer of Control using a select statement). Hence there is no function Is_EDF corresponding to Is_Round_Robin and calls of the subprograms in this package can never raise the exception Dispatching_Policy_Error.

@ If we attempt to apply one of the subprograms in this package to a task that has already terminated then Tasking_Error is raised. If the task parameter is Null_Task_Id then Program_Error is raised.

@ As mentioned earlier, a policy can be selected for a whole partition by for example pragma Task_Dispatching_Policy(Round_Robin_Within_Priorities); whereas in order to mix different policies across different priority levels we can write

  1        pragma Priority_Specific_Dispatching (Round_Robin_Within_Priority, 1, 1);
  2        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 10);
  3        pragma Priority_Specific_Dispatching (FIFO_Within_Priority, 11, 24);

@ This sets Round Robin at priority level 1, EDF at levels 2 to 10, and FIFO at levels 11 to 24. This means for example that none of the EDF tasks can run if any of the FIFO ones can. In other words if any tasks in the highest group can run then they will do so and none in the other groups can run. The scheduling within a range takes over only if tasks in that range can go and none in the higher ranges can.

@ Note that if we write

  1        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 5);
  2        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 6, 10);

@ then this is not the same us

  1        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 10);

@ despite the fact that the two ranges in the first case are contiguous. This is because in the first case any task in the 6 to 10 range will take precedence over any task in the 2 to 5 range whatever the deadlines. If there is just one range then only the deadlines count in deciding which tasks are scheduled.

@ This is emphasized by the fact that the policy name uses Across rather than Within. For other policies such as Round_Robin_Within_Priority two contiguous ranges would be the same as a single range.

@ We conclude this section with a few words about ceiling priorities.

@ In Ada 95, the priority of a task can be changed but the ceiling priority of a protected object cannot be changed. It is permanently set when the object is created using the pragma Priority. This is often done using a discriminant so that at least different objects of a given protected type can have different priorities. Thus we might have

  1        protected type PT (P : Priority) is
  2                pragma Priority (P);
  3                ...
  4        end PT;
  5        PO : PT(7); -- ceiling priority is 7

@ The fact that the ceiling priority of a protected object is static can be a nuisance in many applications especially when the priority of tasks can be dynamic. A common workaround is to give a protected object a higher ceiling than needed in all circumstances (often called "the ceiling of ceilings"). This results in tasks having a higher active priority than necessary when accessing the protected object and this can interfere with the processing of other tasks in the system and thus upset overall schedulability. Moreover, it means that a task of high priority can access an object when it should not (if a task with a priority higher than the ceiling priority of a protected object attempts to access the object then Program_Error is raised – if the object has an inflated priority then this check will pass when it should not).

@ This difficulty is overcome in Ada 2005 by allowing protected objects to change their priority. This is done through the introduction of an attribute Priority which applies just to protected objects. It can only be accessed within the body of the protected object concerned.

@ As an example a protected object might have a procedure to change its ceiling priority by a given amount. This could be written as follows

  1        protected type PT is
  2                procedure Change_Priority (Change : in Integer);
  3                ...
  4        end;
  5        protected body PT is
  6                procedure Change_Priority (Change : in Integer) is
  7                begin
  8                        ... -- PT'Priority has old value here
  9                        PT'Priority := PT'Priority + Change;
 10                        ... -- PT'Priority has new value here
 11                        ...
 12                end Change_Priority;
 13                ...
 14        end PT;

@ Changing the ceiling priority is thus done while mutual exclusion is in force. Although the value of the attribute itself is changed immediately the assignment is made, the actual ceiling priority of the protected object is only changed when the protected operation (in this case the call of Change_ Priority) is finished.

@ Note the unusual syntax. Here we permit an attribute as the destination of an assignment statement.

@ This happens nowhere else in the language. Other forms of syntax were considered but this seemed the most expressive.

Rationale for Ada 2005: Tasking and Real-Time

@ENGRUSTOPBACKNEXT

5. Планирование и диспетчеризация

@ Другая область повышения гибкости в Аде 2005 является область политики диспетчеризации задач. На Аде 95 единственная предопределенная политика - FIFO_Within_Priorities, хотя и другая политика разрешена. Ада 2005 обеспечивает дальнейшие прагмы, политики и пакеты которые облегчают множество различных механизмов таких как неприоритетное прерывание в пределах приоритетов, знакомый Rround Robin, используя timeslicing, и позже приветствуемая политика Earliest Deadline First (EDF). Кроме того, возможно смешивать различные политики согласно приоритетному уровню в пределах разделения.

@ Чтобы упорядочить эти изменения, Секция D.2 (Планирование Приоритета) Справочного описания была реорганизована следующим образом:

@ Полный контроль предоставлен следующими двумя прагмами:

  1        pragma Task_Dispatching_Policy (policy_identifier);
  2        pragma Priority_Specific_Dispatching (policy_identifer, first_priority_expression, last_priority_expression);

@ Прагма Task_Dispatching_Policy, которая уже существует в Аде 95 применяет ту же самую политику в течение целого разделения. Прагма Priority_Specific_Dispatching является новой в Аде 2005 и может использоваться чтобы установить различную политику для различных диапазонов приоритетных уровней.

@ Полный набор предопределенной политики в Аде 2005 - FIFO_Within_Priorities - Он уже, существует в Аде 95. В пределах каждого приоритетного уровня задачи выполняются в порядке очереди FIFO. Кроме того, задача может выгрузить задачу более низкого приоритета.

@ Non_Preemptive_FIFO_Within_Priorities - Это новое в Аде 2005. В пределах каждого приоритетного уровня задачи выполняются пока не завершатся или пока они не будут блокированы или выполнять оператор задержки.

@ Задача не может быть выгружена другой более высокого приоритета. Этот вид политики широко используется в приложениях высокой целостности.

@ Round_Robin_Within_Priorities - Это новое в Аде 2005. В пределах каждого приоритетного уровня каждая задача имеет свой временной интервал, который может быть определен. Это - очень традиционная политика, широко используемая с самых ранних дней параллельного программирования.

@ EDF_Across_Priorities - Это новое в Аде 2005. Оно обеспечивает механизм Earliest Deadline First (Самый ранний Крайний срок Сначала) диспетчеризации. Который состоит в том, что в пределах диапазона приоритетных уровней, у каждой задачи есть крайний срок до истечения которого задача должна быть отрабработана. Это - фешенебельная новая политика имеет математически доказуемые преимущества по эффективности.

@ Для детальной информации об этой политике обрящайтесь к книге Alan Burns and Andy Wellings [4].

@ Этой политикой управляет пакет Ada.Dispatching плюс два дочерних пакета. Корневой пакет имеет следующую спецификацию:

  1        package Ada.Dispatching is
  2                pragma Pure(Dispatching);
  3                Dispatching_Policy_Error: exception;
  4        end Ada.Dispatching;

@ Как можнр видеть, этот корневой пакет просто объявляет исключение Dispatching_Policy_Error которое используется дочерними пакетами.

@ Дочерний пакет Round_Robin осуществляет регулировку квантов времени для квантования времени в пределах одного или более приоритетных уровней. Его спецификация:

  1        with System; use System;
  2        with Ada.Real_Time; use Ada.Real_Time;
  3        package Ada.Dispatching.Round_Robin is
  4                Default_Quantum : constant Time_Span := implementation-defined;
  5                procedure Set_Quantum (Pri : in Priority, Quantum : in Time_Span);
  6                procedure Set_Quantum (Low, High : in Priority; Quantum : in Time_Span);
  7                function Actual_Quantum (Pri : Priority) return Time_Span;
  8                function Is_Round_Robin (Pri : Priority) return Boolean;
  9        end Ada.Dispatching.Round_Robin;

@ Процедуры Set_Quantum позволяют кванту времени использоваться для квантования времени, которое будет установлено для одного или диапазона приоритетных уровней. Значение по умолчанию определяется константой Default_Quantum. Функция Actual_Quantum позволяет нам узнать текущее значение кванта, используемого для специфического приоритетного уровня. Его идентификатор отражает факт, что реализация, возможно, не в состоянии применить точное фактическое значение, данное в запросе Set_Quantum. Функция Is_Round_Robin позволяет нам проверить, была ли политика циклического алгоритма применена к данному уровню приоритета. Если мы пытаемся сделать нечто глупое, например установить квант для приоритетного уровня к которому политика циклического алгоритма не применима, тогда возбуждается исключение Dispatching_Policy_Error.

@ Другая новая политика касается пределов и управляется новой прагмой Relative_Deadline и дочернего пакета Dispatching.EDF. Синтаксис прагмы такой: pragma Relative_Deadline (relative_deadline_expression); Крайний срок задачи это свойство подобное приоритету, и они оба используются для планирование (scheduling). У каждой задачи есть приоритет типа Integer, и у каждой задачи есть крайний срок типа Ada.Real_Time.Time. Приоритеты могут быть установлены, когда задача создана прагмой pragma Priority:

  1        task T is
  2                pragma Priority (P);

@ и крайние сроки могут так же быть установлены прагмой Relative_Deadline таким образом:

  1        <b>task</<code>b> T <b>is</<code>b>
  2                <b>pragma</<code>b> Relative_Deadline (RD);

@ У выражения RD типа Ada.Real_Time.Time_Span. Отметим, что прагма устанавливает родственника а не абсолютный крайний срок. Начальный абсолютный крайний срок задачи - Ada.Real_Time.Clock + RD, где запрос Clock сделан между созданием задачи и началом его активации.

@ Обе прагмы Priority и Relative_Deadline могут появиться в основной подпрограмме, и они тогда относятся к задаче среды. Если они появляются в любой другой подпрограмме тогда, они игнорируются. Оба свойства могут также быть установлены через дискриминант. В случае приоритетов мы можем написать:

  1        task type TT (P : Priority) is
  2                pragma Priority (P);
  3                ...
  4        end;
  5        High_Task : TT (13);
  6        Low_Task  : TT (7);

@ Мы не можем сделать прямое назначение для пределов, потому что Time_Span является приватным и так не дискретный.

@ Мы должны использовать ссылочный дискриминант таким образом:

  1        task type TT (RD : access Timespan) is
  2                pragma Relative_Deadline (RD.all);
  3                ...
  4        end;
  5        One_Sec   : aliased constant Time_Span := Seconds (1);
  6        Ten_Mins  : aliased constant Time_Span := Minutes (10);
  7        Hot_Task  : TT (One_Sec'Access);
  8        Cool_Task : TT (Ten_Mins'Access);

@ Отметим, что функции Seconds и Minutes были добавлены к пакету Ada.Real_Time. Существующие функции Nanoseconds, Microseconds и Milliseconds в Аде 95 осуществляют удобную спецификацию коротких интервалов реального времени (значения типа Time_Span). Однако, спецификация более длинных интервалов, таких как четыре минуты вынуждало писать Milliseconds (240_000) или возможно 4 * 60 * Milliseconds (1000). Ввиду факта, что планирование EDF и таймеры (см. Секцию 6), вероятно, потребовали бы более длинных времен, функции Seconds и Minutes добавлены к Аде 2005. Нет никакой функции Hours, потому что диапазон отрезков не предусматривает временных интервалов больше 3600 секунд так или иначе.

@ Если создаётся задача и у нее нет прагмы Priority тогда, его начальный приоритет равен приоритету задачи, которая её создаёт. Если у задачи нет прагмы Relative_Deadline тогда, его начальный абсолютный крайний срок равен константе Default_Deadline из пакета Ada.Dispatching.EDF; у этой константы есть значение Ada.Real_Time.Time_Last (эффективно конец области).

@ Приоритетами можно динамически управлять подпрограммами из пакета Ada.Dynamic_Priorities и пределами можно так же управлять подпрограммы из пакета Ada.Dispatching.EDF спецификация которого:

  1        with Ada.Real_Time; use Ada.Real_Time;
  2        with Ada.Task_Identification; use Ada.Task_Identification;
  3        package Ada.Dispatching.EDF is
  4                subtype Deadline is Ada.Real_Time.Time;
  5                Default_Deadline : constant Deadline := Time_Last;
  6                procedure Set_Deadline
  7                        (D : in Deadline; T : in Task_Id := Current_Task);
  8                procedure Delay_Until_And_Set_Deadline
  9                        (Delay_Until_Time : in Time; Deadline_Offset : in Time_Span);
 10                function Get_Deadline (T : Task_Id := Current_Task) return Deadline;
 11        end Ada.Dispatching.EDF;

@ Подтип Dadline был объявлен только как удобное сокращение. Константа Default_Deadline установлена в конец области как было уже упомянуто. Процедура Set_Deadline устанавливает крайний срок соответствующей задачи к значению параметра D. Многословный Delay_Until_And_Set_Deadline задерживает соответствующую задачу до значения Delay_Until_Time, и устанавливает её крайний срок, чтобы быть интервальным Deadline_Offset с того времени - это полезно для периодических задач. Функция Get_Deadline позволяет нам найти текущий крайний срок задачи.

@ Важно отметить, что этот пакет может использоваться, чтобы установить и восстановить пределы для задач, являются ли они подлежащими диспетчеризации EDF. Мы могли например использовать ATC на переполненном крайнем сроке (ACT = Асинхронная Передача Контроля, используя оператора выбора). Следовательно нет никакой функции Is_EDF, соответствующей Is_Round_Robin, и запросы подпрограмм в этом пакете никогда не могут вызывать исключение Dispatching_Policy_Error.

@ Если мы пытаемся применить одну из подпрограмм в этом пакете к задаче, которая уже закончилась тогда возбуждается исключение Tasking_Error. Если параметр задачи - Null_Task_Id тогда возбуждается исключение Program_Error.

@ Как было упомянуто ранее, политика может быть выбрана для целого разделения например прагмой Task_Dispatching_Policy (Round_Robin_Within_Priorities); тогда чтобы смешать различные политики через различные приоритетные уровни мы можем написать:

  1        pragma Priority_Specific_Dispatching (Round_Robin_Within_Priority, 1, 1);
  2        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 10);
  3        pragma Priority_Specific_Dispatching (FIFO_Within_Priority, 11, 24);

@ Это устанавливает Циклический алгоритм (Round Robin) на уровень приоритета 1, EDF на уровени 2 - 10, и FIFO на уровнях 11 - 24. Это означает например, что ни одна из задач EDF не может работать, если имеется какая - нибудь задача в FIFO. Другими словами, если какие-нибудь задачи в самой высокой группе могут работать тогда, ни в одной другой группе не может осуществляться работа. Планирование в пределах диапазона вступает во владение, только если задачи ни в одном из более высоких диапазонов не могут работать.

@ Отметим это, если мы пишем:

  1        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 5);
  2        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 6, 10);

@ тогда это не то же самое что:

  1        pragma Priority_Specific_Dispatching (EDF_Across_Priorities, 2, 10);

@ несмотря на то, что два диапазона в первом случае являются смежными. Это - то, потому что в первом случае любая задача в этих 6 - 10 диапазонах будет иметь приоритет по любой задаче в этих 2 - 5 диапазонах вообще пределы. Если есть только один диапазон тогда только счет пределов в решении, какие задачи намечаются.

@ Это подчеркнуто тем фактом, что название политики использует термин Across (Через), а не Within (В пределах). Для другой политики, такой как Round_Robin_Within_Priority два смежных диапазона были бы тем же самым как одним диапазоном.

@ Мы заключаем эту секцию с несколькими словами о потолке приоритетов.

@ В Аде 95, может быть изменен приоритет задачи, но приоритет потолка защищенного объекта не может быть изменен. Это надолго установлено, когда объект создан, используя прагмы Priority. Это часто делается, используя дискриминант так, чтобы по крайней мере различные объекты данного защищенного типа могли иметь различные приоритеты. Таким образом мы могли бы написать:

  1        protected type PT (P : Priority) is
  2                pragma Priority (P);
  3                ...
  4        end PT;
  5        PO : PT(7); -- ceiling priority is 7

@ Факт, что приоритет потолка защищенного объекта является статическим, может быть неприятностью во многих приложениях особенно, когда приоритет задач может быть динамическим. Общая работа должна дать защищенному объекту более высокий потолок чем необходимый при всех обстоятельствах (часто названный "потолок потолков"). Это приводит к задачам, имеющим более высокий активный приоритет чем необходимый, обращаясь к защищенному объекту, и это может столкнуться с обработкой других задач в системе и, таким образом, опрокинуть повсюду schedulability. Кроме того, это означает, что задача первоочередности может обратиться к объекту, когда это не должен (если задача с приоритетом выше чем приоритет потолка защищенного объекта пытается обратиться к объекту тогда, возбуждается исключение Program_Error если у объекта будет надутый приоритет тогда, то эта проверка пройдет, когда это не должно).

@ Эта трудность преодолена в Аде 2005, позволяя защищенным объектам изменить их приоритет. Это сделано через введение атрибута Priority, который применяется только к защищенным объектам. К этому можно только обратиться в пределах тела соответствующего защищенного объекта.

@ Как пример у защищенного объекта могла бы быть процедура, чтобы изменить ее приоритет потолка на некоторую величину. Это могло быть написано следующим образом:

  1        protected type PT is
  2                procedure Change_Priority (Change : in Integer);
  3                ...
  4        end;
  5        protected body PT is
  6                procedure Change_Priority (Change : in Integer) is
  7                begin
  8                        ... -- PT'Priority has old value here
  9                        PT'Priority := PT'Priority + Change;
 10                        ... -- PT'Priority has new value here
 11                        ...
 12                end Change_Priority;
 13                ...
 14        end PT;

@ Изменение приоритета потолка, таким образом, сделано, в то время как взаимное исключение находится в силе. Хотя значение самого атрибута немедленно изменено, присваивание сделано, фактический приоритет потолка защищенного объекта изменится только когда защищенная операция (в этом случае вызов Change_Priority) будет закончена.

@ Отметьте необычный синтаксис. Здесь мы разрешаем атрибут как адресат оператора присваивания.

@ Это еще не случалось нигде в языке. Рассматривались и другие формы синтаксиса, но это показалось самым выразительным.

@ ENG RUS

TOP BACK NEXT

2010-10-24 00:26:55

. .