9.4 Protected Units and Protected Objects
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
A protected object provides coordinated access to shared data, through calls on its visible protected operations, which can be protected subprograms or protected entries. A protected unit is declared by a protected declaration, which has a corresponding protected_body
. A protected declaration may be a protected_type_declaration
, in which case it declares a named protected type; alternatively, it may be a single_protected_declaration
, in which case it defines an anonymous protected type, as well as declaring a named protected object of that type.
Syntax
2/3protected_type_declaration
::=
protected type defining_identifier
[known_discriminant_part
]
[aspect_specification
] is
[new interface_list
with]
protected_definition
;
3/3single_protected_declaration
::=
protected defining_identifier
[aspect_specification
] is
[new interface_list
with]
protected_definition
;
4protected_definition
::=
{ protected_operation_declaration
}
[ private
{ protected_element_declaration
} ]
end [protected_identifier
]
5/1{8652/0009} protected_operation_declaration
::=
subprogram_declaration
| entry_declaration
| aspect_clause
6protected_element_declaration
::=
protected_operation_declaration
| component_declaration
declarative_part
s and task_definition
s as well. protected_body
::=
protected body defining_identifier
[aspect_specification
] is
{ protected_operation_item
}
end [protected_identifier
];
8/4{8652/0009} protected_operation_item
::=
subprogram_declaration
| subprogram_body
| null_procedure_declaration
| expression_function_declaration
| entry_body
| aspect_clause
9If a protected_identifier
appears at the end of a protected_definition
or protected_body
, it shall repeat the defining_identifier
.
Paragraph 10 was deleted.
Static Semantics
11/2A protected_definition
defines a protected type and its first subtype. The list of protected_operation_declaration
s of a protected_definition
, together with the known_discriminant_part
, if any, is called the visible part of the protected unit. [ The optional list of protected_element_declaration
s after the reserved word private is called the private part of the protected unit.]
For a protected declaration with an interface_list
, the protected type inherits user-defined primitive subprograms from each progenitor type (see 3.9.4), in the same way that a derived type inherits user-defined primitive subprograms from its progenitor types (see 3.4). If the first parameter of a primitive inherited subprogram is of the protected type or an access parameter designating the protected type, and there is a protected_operation_declaration
for a protected subprogram or single entry with the same identifier within the protected declaration, whose profile is type conformant with the prefixed view profile of the inherited subprogram, the inherited subprogram is said to be implemented by the conforming protected subprogram or entry using an implicitly declared nonabstract subprogram which has the same profile as the inherited subprogram and which overrides it.
Legality Rules
11.2/2A protected declaration requires a completion[, which shall be a protected_body
,] and every protected_body
shall be the completion of some protected declaration.
protected_body
is allowed. [Each interface_subtype_mark
of an interface_list
appearing within a protected declaration shall denote a limited interface type that is not a task interface.]
interface_list
only name interface types, and limits the descendants of the various kinds of interface types. Only a limited, protected, or synchronized interface can have a protected type descendant. Nonlimited or task interfaces are not allowed, as they offer operations that a protected type does not have. The prefixed view profile of an explicitly declared primitive subprogram of a tagged protected type shall not be type conformant with any protected operation of the protected type, if the subprogram has the same defining name as the protected operation and the first parameter of the subprogram is of the protected type or is an access parameter designating the protected type.
For each primitive subprogram inherited by the type declared by a protected declaration, at most one of the following shall apply:
- the inherited subprogram is overridden with a primitive subprogram of the protected type, in which case the overriding subprogram shall be subtype conformant with the inherited subprogram and not abstract; or
- the inherited subprogram is implemented by a protected subprogram or single entry of the protected type, in which case its prefixed view profile shall be subtype conformant with that of the protected subprogram or entry.
If neither applies, the inherited subprogram shall be a null procedure. In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit.
If an inherited subprogram is implemented by a protected procedure or an entry, then the first parameter of the inherited subprogram shall be of mode out or in out, or an access-to-variable parameter. If an inherited subprogram is implemented by a protected function, then the first parameter of the inherited subprogram shall be of mode in, but not an access-to-variable parameter.
If a protected subprogram declaration has an overriding_indicator
, then at the point of the declaration:
- if the
overriding_indicator
is overriding, then the subprogram shall implement an inherited subprogram; 11.12/2 - if the
overriding_indicator
is not overriding, then the subprogram shall not implement any inherited subprogram.
In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit.
Dynamic Semantics
12[The elaboration of a protected declaration elaborates the protected_definition
. The elaboration of a single_protected_declaration
also creates an object of an (anonymous) protected type.]
full_type_declaration
and an object_declaration
. [The elaboration of a protected_definition
creates the protected type and its first subtype;] it also includes the elaboration of the component_declaration
s and protected_operation_declaration
s in the given order.
[As part of the initialization of a protected object, any per-object constraints (see 3.8) are elaborated.]
The elaboration of a protected_body
has no other effect than to establish that protected operations of the type can from then on be called without failing the Elaboration_Check.
The content of an object of a given protected type includes:
- The values of the components of the protected object, including (implicitly) an entry queue for each entry declared for the protected object;
- A representation of the state of the execution resource associated with the protected object (one such resource is associated with each protected object).
[The execution resource associated with a protected object has to be acquired to read or update any components of the protected object; it can be acquired (as part of a protected action — see 9.5.1) either for concurrent read-only access, or for exclusive read-write access.]
As the first step of the finalization of a protected object, each call remaining on any entry queue of the object is removed from its queue and Program_Error is raised at the place of the corresponding entry_call_statement
.
procedure Main is
task T is
entry E;
end T;
20.ctask body T is
protected PO is
entry Ee;
end PO;
20.dprotected body PO is
entry Ee when False is
begin
null;
end Ee;
end PO;
begin
accept E do
requeue PO.Ee;
end E;
end T;
begin
T.E;
end Main;
Bounded (Run-Time) Errors
20.1/2It is a bounded error to call an entry or subprogram of a protected object after that object is finalized. If the error is detected, Program_Error is raised. Otherwise, the call proceeds normally, which may leave a task queued forever.
with Ada.Finalization.Controlled;
package Window_Manager is
...
type Root_Window is new Ada.Finalization.Controlled with private;
type Any_Window is access all Root_Window;
...
private
...
procedure Finalize (Object : in out Root_Window);
...
end Window_Manager;
20.j/2package body Window_Manager is
protected type Lock is
entry Get_Lock;
procedure Free_Lock;
...
end Lock;
20.k/2Window_Lock : Lock;
20.l/2procedure Finalize (Object : in out Root_Window) is
begin
Window_Lock.Get_Lock;
...
Window_Lock.Free_Lock;
end Finalize;
...
A_Window : Any_Window := new Root_Window;
end Window_Manager;
access_definition
, the name of the protected unit denotes the current instance of the unit (see 8.6), rather than the first subtype of the corresponding protected type (and thus the name cannot be used as a subtype_mark
). subtype_mark
in an anonymous access type. In addition, it is possible to refer to some other subtype of the protected type within its body, presuming such a subtype has been declared between the protected_type_declaration
and the protected_body
. selected_component
can be used to denote a discriminant of a protected object (see 4.1.3). Within a protected unit, the name of a discriminant of the protected type denotes the corresponding discriminant of the current instance of the unit.assignment_statement
s and predefined equality operators.protected_body
define the actions that take place upon calls to the protected operations.Component_declaration
s are disallowed in a protected_body
because, for efficiency, we wish to allow the compiler to determine the size of protected objects (when not dynamic); the compiler cannot necessarily see the body. Furthermore, the semantics of initialization of such objects would be problematic — we do not wish to give protected objects complex initialization semantics similar to task activation.entry_declaration
s, since an entry involves an implicit component — the entry queue. Examples
26Example of declaration of protected type and corresponding body:
protected type Resource is
entry Seize;
procedure Release;
private
Busy : Boolean := False;
end Resource;
28protected body Resource is
entry Seize when not Busy is
begin
Busy := True;
end Seize;
29procedure Release is
begin
Busy := False;
end Release;
end Resource;
30Example of a single protected declaration and corresponding body:
protected Shared_Array is
-- Index, Item, and Item_Array are global types
function Component (N : in Index) return Item;
procedure Set_Component(N : in Index; E : in Item);
private
Table : Item_Array(Index) := (others => Null_Item);
end Shared_Array;
32protected body Shared_Array is
function Component(N : in Index) return Item is
begin
return Table(N);
end Component;
33procedure Set_Component(N : in Index; E : in Item) is
begin
Table(N) := E;
end Set_Component;
end Shared_Array;
34Examples of protected objects:
Control : Resource;
Flags : array(1 .. 100) of Resource;
Extensions to Ada 83
Extensions to Ada 95
Overriding_indicator
s can be used to specify whether or not a protected operation implements a primitive operation. Wording Changes from Ada 95
assignment_statement
s).Incompatibilities With Ada 2005
Extensions to Ada 2005
aspect_specification
can be used in a protected_type_declaration
, a single_protected_declaration
, and a protected_body
. This is described in 13.1.1.