Title: Ada 95 Protected Objects for Synchronizing Shared Data Structures
1Ada 95 Protected Objects for Synchronizing Shared
Data Structures
Currie Colket The MITRE Corporation Phone (703)
883-7381 Email colket_at_mitre.org
colket_at_acm.org DC SIGAda 14 March 2002
SIGAda Home Page ? http//www.acm.org/sigada
Acknowledgement and Thanks to Bill Thomas for his
help and ideas.
2So What Are Protected Objects?
3Overview
- Introduction
- Features that Make Protected Objects Attractive
- Ada 95 RM View of Protected Objects
- Designing Software With Protected Objects
- Design Considerations
- Ada 95 Quality and Style Guide
- Guide for the Use of the Ada Programming Language
in High Integrity Systems (ISO TR 15942) - Automatic Analysis of Protected Objects Using
ASIS - Conclusion
4Motivation For Protected Object - 1
package Protected_Position is procedure Read
(X out Position) procedure Write (X in
Position) end Protected_Position package body
Protected_Position is Protected_Object
Position (0.0,0.0) procedure Read (X
out Position) is begin X
Protected_Object end Read
procedure Write (X in Position) is begin
Protected_Object X end Write end
Protected_Position
Consider
type Position is record Latitude
Float Longitude Float end
record
- And the effects of
- Time Slicing
- Expiration of a delay of a higher priority task
5Motivation For Protected Object - 2
protected Protected_Position is procedure
Read (X out Position) procedure Write (X
in Position) private Protected_Object
Position (0.0,0.0) end Protected_Position
With Mutual Exclusion
protected body Protected_Position is
procedure Read (X out Position) is begin
X Protected_Object end Read
procedure Write (X in Position) is
begin Protected_Object X end
Write end Protected_Position
Still
type Position is record Latitude
Float Longitude Float end
record
6IntroductionProtected Objects
- Protected objects provide
- coordinated access to shared data
- - through calls on its visible protected
operations, - Protected Operations can be
- Protected subprograms or
- Protected entries.
- Protected units are declared by a
- Protected declaration, and
- Corresponding protected_body.
- Protected declaration may be a
- Protected_type_declaration
- - in which case it declares a named protected
type - Single_protected_declaration
- - in which case it defines an anonymous
protected type, - - as well as declaring a named protected object
of that type
Every Protected Declaration Required a Protected
Body
7Features That Make Protected Objects Attractive
as a Building Block - 1
- Scalability - Synchronization mechanism scales
smoothly from a single processor to a
multiprocessor. - Adaptability - Additional protected operations
may be added to a protected type without the need
to modify the existing specification (e.g., use
explicit signals and explicitly signal all
possible waiting tasks.) - Modularity - All of the operations of a given
critical region are identified in the
specification, and the operationss are
encapsulated within the body. The protected data
is encapsulated within the private part. - Efficiency - Size and initialization requirements
are known at compile time, because all entries
and data components are declared in the
specification. - Allocated statically (directly on the stack)
rather than via dynamic allocation - No extra context switches are required to
service waiting clients (since task changing
state may directly execute entry bodies whose
barriers become true) - Non-queued locking may be used to implement
mutual exclusion of a protected object because no
blocking is permitted during the execution of a
protected operation.
8Features That Make Protected Objects Attractive
as a Building Block - 2
Expressiveness - Explicit distinctions between
read-only operations (functions), read-write
operations (procedures), and possibly blocking
operations (entries). This distinction is vital
in analyzing a real-time program for correctness,
including freedom from deadlock. Compatibility
Compatible with Ada95 tasking. Interrupt
Handling - Well suited to act as an interrupt
handler for a number of reasons they both
typically have a short bounded execution time, do
not arbitrarily block, have a limited context and
finally they both have to integrate with the
priority model. The nonblocking critical region
matches the needs of an interrupt handler, as
well as the needs of non-interrupt-level code to
synchronize with an interrupt handler. The entry
barrier construct allows an interrupt handler to
signal a normal task by changing the state of a
component of the protected object and thereby
making a barrier true.
9IntroductionSimple Example of Protected Objects
protected Counter is procedure Increment
(New_Value out Positive) function
Get_Counter return Integer private
Data Integer 0 end Counter protected
body Counter is procedure Increment
(New_Value out Positive) is begin
Data Data 1 New_Value Data
end Increment function Get_Counter is
begin return Data end
Get_Counter end Counter
Counter
Task may increment it by Counter.Increment
(New_Value gt X) Task may obtain the Counter
value by A Counter.Get_Counter
10Ada 95 RM Protected Objects
- 3.X Declarations and Types
- 9.0 Tasks and Synchronization
- 9.4 Protected Units and Protected Objects
- 9.5 Intertask Communication
- .1 Protected Subprograms and Protected Actions
- .2 Entries and Accept Statements
- .3 Entry Calls
- .4 Requeue
- 9.8 Abort
- 9.9 Task and Entry Attributes
- 10.1.3 Progrm Structure and Compilation Issues
- C.6 Shared Variable Control
11Ada 95 RM 3.0 Declarations and Types
(Miscellaneous Syntax)
full_type_declaration type
defining_identifier known_discriminant_part is
type_definition task_type_declaration
protected_type_declaration object_declarat
ion defining_identifier_list
aliased constant subtype_indication
expression defining_identifier_list
aliased constant array_type_definition
expression single_task_declaration
single_protected_declaration access_to_subprog
ram_definition access protected
procedure parameter_profile access
protected function parameter_and_result_profile
proper_body subprogram_body
package_body task_body protected_body
Ada LRM 3.2.1
Ada LRM 3.3.1
Ada LRM 3.10
Ada LRM 3.11
12Ada 95 RM 9.4 Protected Units and Protected
Objects - 1
- single_protected_declaration
- protected defining_identifier is
protected_definition - protected_type_declaration
- protected type defining_identifier
known_discriminant_part is protected_definition
- protected_definition
- protected_operation_declaration
- private
- protected_element_declaration
- end protected_identifier
-
Visible Part of the Protected Unit
Private Part of the Protected Unit
13Ada 95 RM 9.4 Protected Units and Protected
Objects
- protected_operation_declaration
- subprogram_declaration entry_declaration
aspect_clause - protected_element_declaration
protected_operation_declaration
component_declaration - protected_body
- protected body defining_identifier is
- protected_operation_item
- end protected_identifier
-
- protected_operation_item subprogram_declaratio
n - subprogram_body entry_body
aspect_clause
aspect_clause Chapter 13
Protected_body from Chapter 10
14Ada 95 RM Example of Declaration of Protected
Type
protected body Resource is entry Seize
when not Busy is begin Busy
True end Seize procedure Release
is begin Busy False end
Release end Resource
protected type Resource is entry Seize
procedure Release private Busy
Boolean False end Resource
Examples of protected objects Control
Resource Flags array (1 .. 4) of
Resource
15Ada 95 RM Example of Single Protected Declaration
protected Shared_Array is function
Get_Component (N in Index) return Item
procedure Set_Component(N in Index E in
Item) private Table Item_Array(Index)
(others gt Null_Item) end Shared_Array
Note Index, Item, Item_Array are global types
protected body Shared_Array is function
Get_Component(N in Index) return Item is
begin return Table(N) end
Get_Component procedure Set_Component(N
in Index E in Item) is begin
Table(N) E end Set_Component end
Shared_Array
Not allowed to declare new objects
Examples Shared_Array.Set_Component(N, E) E
Shared_Array. Get_Component(M)
16Ada 95 RM 9.4 Protected Units and Protected
Objects
- 9.4 Notes
- A protected type is a limited type and hence has
neither an assignment operation nor predefined
equality operators. - The bodies of the protected operations given in
the protected_body define the actions that take
place upon calls to the protected operations. - 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.
17Ada 95 RM 9.5 Intertask Communications - 1
- Primary means for Intertask Communication is
provided by - Calls on Entries and
- Calls on Protected Subprograms.
- Calls on protected subprograms allow coordinated
access to shared data objects. - Entry calls allow for blocking the caller
- Until a given condition is satisfied (e.g.,
entry is open), and - Then communicating data or control information
- - Directly with another task or
- - Indirectly via a shared protected object.
(for Protected Objects)
18Ada 95 RM 9.5 Intertask Communications - 2
Model Entries always have barrier
conditions Eggshell Model John Barnes
wrote in describing the Eggshell Model It must
be understood that the barrier protection
mechanism is superimposed upon the natural mutual
exclusion of the protected construct thus giving
two distinct levels of protection
Tasks waiting on barrier (in entry queues)
?
Task executing (at most one)
Guard
Get_Item
?
Set_Item
Tasks outside (in unstructured way)
19Ada 95 RM 9.5 Intertask Communications - 3
Renamings allowed
20Ada 95 RM 9.5.1 Protected Subprograms and
Protected Actions - 1
- Protected Subprogram
- Subprograms declared immediately within a
protected_definition. - Protected Procedures provide
- Exclusive read-write access to the data of a
protected object - Protected Functions provide
- Concurrent read-only access to the data
For functions Blocked If procedure accessing
For procedures Blocked If functions accessing
Not really called blocked
21Ada 95 RM 9.5.1 Protected Subprograms and
Protected Actions - 2
Bounded (Run-Time) Errors During a protected
action, it is a bounded error to invoke an
operation that is potentially blocking.
Potentially blocking operations a
select_statement an accept_statement
an entry_call_statement a
delay_statement an abort_statement
task creation or activation an
external call on a protected subprogram (or an
external requeue) with the same
target object as that of the protected action
a call on a subprogram whose body contains
a potentially blocking operation
(especially I/O).
If the bounded error is detected
Program_Error is raised else Bounded error
might result in deadlock or a (nested)
protected action on the same target object.
22Ada 95 RM 9.5.1 Protected Subprograms and
Protected Actions - 3
- Notes for 9.5.1
- If two tasks both try to start a protected
action on a protected object, and at most one is
calling a protected function, then only one task
can proceed. Although the other task cannot
proceed, it is not considered blocked, and it
might be consuming processing resources while it
awaits its turn. - There is no language-defined ordering or
queuing presumed for tasks competing to start a
protected action - Priority Ceiling Locking is possible with
pragma Locking_Policy (See D.3) - Body of a protected function can contain
internal calls on other protected functions, but
not protected procedures - Body of a protected procedure can contain
internal calls on both protected functions and
procedures. - From within a protected action, an internal
call on a protected subprogram, or an external
call on a protected subprogram with a different
target object is not considered a potentially
blocking operation.
23Ada 95 RM 9.5.2 Entries and Accept Statements - 1
entry_declaration entry
defining_identifier (discrete_subtype_definition)
parameter_profile entry_body entry
defining_identifier entry_body_formal_part
entry_barrier is declarative_part
begin handled_sequence_of_statements
end entry_identifier entry_body_formal_part
(entry_index_specification)
parameter_profile entry_barrier when
condition entry_index_specification for
defining_identifier in discrete_subtype_definition
Entry_declarations are only allowed for task
declarations and protected declarations.
Note barrier is required
Entry_declarations, with the corresponding
entry_bodies are used to define potentially
queued operations on protected objects.
Condition for entry_barrier can be any private
or global data except for the object of the
parameter_profile - Index Discriminant OK
24Ada 95 RM 9.5.2 Entries and Accept Statements - 2
- Notes
- parameter modes are the same as for a
subprogram_declaration and have the same meaning - An entry_declaration with a discrete_subtype_def
inition declares a family of distinct entries
having the same profile. - An entry_body is executed when the condition of
the entry_barrier evaluates to True and a caller
of the corresponding single entry, or entry of
the corresponding entry family, has been selected - A task entry has 0 or more corresponding
accept_statements a protected entry has exactly
one corresponding entry_body. - A return_statement or a requeue_statement may
be used to complete the execution of an
entry_body.
25Ada 95 RM 9.5.3 Entry Calls - 1
entry_call_statement entry_name
actual_parameter_part
protected body Resource is entry Seize when
not Busy is begin Busy True
end Seize procedure Release is
begin Busy False end Release
end Resource
For Device array(1 .. 4) of
Resource Device(3).Seize
26Ada 95 RM 9.5.3 Entry Calls - 2 Notes
- An entry of a protected object is open if the
condition of the entry_barrier of the
corresponding entry_body evaluates to True
otherwise it is closed. - If open, the entry call is said to be selected
immediately, and the execution of the call
proceeds with the entry_body - If closed, the entry call is added to an entry
queue and the call remains queued until it is
selected or cancelled there is a separate
(logical) entry queue for each entry family for
protected object - If an exception is raised during the execution
of an entry_body, it is propagated to the
corresponding caller - If evaluation of barrier propagates an
exception, Program_Error is propagated to all
current callers of all entries of the protected
object. - Entry Queuing Policies selected with pragma
Queuing Policy (D.4) - Cancellation of a call on an entry of a
protected object is a protected action, and as
such cannot take place while any other protected
action is occurring on the protected object. Like
any protected action, it includes servicing of
the - entry queues (in case some entry barrier depends
on a Count attribute).
27Ada 95 RM 9.5.4 Requeue Statement - 1
A requeue_statement can be used to complete an
entry_body, while redirecting the corresponding
entry call to a new (or the same) entry queue.
requeue_statement requeue entry_name with
abort Notes For the execution of a requeue on
an entry of a target protected object, after
leaving the enclosing callable construct ?
If the requeue is an internal requeue (that is,
the requeue is back on an entry of the
same protected object), the call is added to the
queue of the named entry and the
ongoing protected action continues ? If
the requeue is an external requeue (that is, the
target protected object is not
implicitly the same as the current object), a
protected action is started on the
target object and proceeds as for a normal entry
call.
28Ada 95 RM 9.5.4 Requeue Statement - 2
- Notes (continued)
- If the requeue_statement includes the reserved
words with abort (it is a - requeue-with-abort), then
- - If the original entry call has been
aborted, then the requeue acts as an abort - completion point for the call, and the
call is cancelled and no requeue is - performed
- - If the original entry call was timed (or
conditional), then the original - expiration time is the expiration time
for the requeued call. - If the reserved words with abort do not appear,
then the call remains protected - against cancellation while queued as the result
of the requeue_statement.
29Ada 95 RM 9.8 Abort Statement
An abort_statement causes one or more tasks to
become abnormal, thus preventing any further
interaction with such tasks. When the execution
of a construct is aborted (including that of a
task_body or of a sequence_of_statements), the
execution of every construct included within the
aborted execution is also aborted, except for
executions included within the execution of an
abort-deferred operation the execution of an
abort-deferred operation continues to completion
without being affected by the abort the
following are the abort-deferred operations
a protected action Abort takes
place after the protected is completed.
30Ada 95 RM 9.9 Task and Entry Attributes
- For a prefix E that denotes an entry of a task
or protected unit - E'Count
- Yields the number of calls presently queued on
the entry E of the current instance of the unit.
The value of this attribute is of the type
universal_integer. - Notes
- This attribute is only allowed within the body
of the task or protected unit. - Entry can be either a single entry or an entry
of a family. - Within protected units, algorithms
interrogating the attribute E'Count in the - entry_barrier for the entry E should take
precautions to allow for the - evaluation of the condition of the barrier
both before and after queuing a - given caller.
31Ada 95 RM 10.1.3 Program Structure and
Compilation Issues
body_stub subprogram_body_stub
package_body_stub task_body_stub
protected_body_stub protected_body_stub
protected body defining_identifier is separate
32Ada 95 RM C.6 Shared Variable Control
- Clause specifies representation pragmas that
control use of shared variables -
- pragma Atomic (local_name)
- pragma Volatile (local_name)
- pragma Atomic_Components (array_local_name)
- pragma Volatile_Components
(array_local_name) - For an atomic object (including an atomic
component) all reads and updates of the object as
a whole are indivisible. - For a volatile object all reads and updates of
the object as a whole are performed directly to
memory. - An imported volatile or atomic constant behaves
as a constant (i.e. read-only) with respect to
other parts of the Ada program, but can still be
modified by an external source. - It is illegal to apply pragma to an object or
type if the implementation cannot support the
indivisible reads and updates - Program Error
- local_name denotes
- object_declaration,
- non-inherited component_declaration,
- full_type_declaration.
- array_local_name denotes
- declaration of an array type
- array object of an anonymous type.
33Designing Software With Protected Objects
Overview
- Design Considerations
- (Thoughts on Sharing Resources and Data on
Design) - Ada 95 Quality and Style Guide Recommendations
- Guide for the Use of the Ada Programming
Language in High Integrity Systems (ISO TR 15942)
34Design Considerations Example 1 System Example
System Protected Objects System Devices
(Resources) System Data (e.g.,
Own_Position) Distributed Environment (How many
processors?)
Subsystem Protected Objects Multiple Subsystem
Tasks How critical is timing of data
System Control
Shared Here?
...
Navigation
Sensor Control
Tracking
Fire Control
...
Radar
Infra Red
ESM
Acoustics
How is Data Here?
35Ada 95 Quality Style Guide 3.2.7 Program Name
Units
- Guidelines
- Use nouns descriptive of the data being
protected for protected units. - Examples
- protected Current_Location is -- data
being protected - protected type Guardian is --
noun implying protection - Rationale
- Using these naming conventions creates
understandable code that reads much like natural
language. When verbs are used for actions, such
as subprograms, and nouns are used for objects,
such as the data that the subprogram manipulates,
code is easier to read and understand.
36Ada 95 Quality Style Guide 5.9.9 Programming
Practices
- Guidelines
- Do not invoke a potentially blocking operation
within a protected entry, - a protected procedure, or a protected
function. - Rationale Blocking operations mentioned in Ada95
RM - - Select statement - Accept statement
- Entry-call statement - - Delay statement - Abort statement
- Task creation or activation - - External call on a protected subprogram (or
an external requeue) with - the same target object as that of the
protected action - - Call on a subprogram whose body contains a
potentially blocking operation - Invoking any of these potentially blocking
operations could lead either to a bounded error
being detected or to a deadlock situation. In the
case of bounded error, the exception
Program_Error is raised. In addition, avoid
calling routines within a protected entry,
procedure, or function that could directly or
indirectly invoke operating system primitives or
similar operations that can cause blocking that
is not visible to the Ada run-time system.
37Ada 95 Quality Style Guide Section 6.1.16.1
Concurrency Options 6.1.1 Protected Objects 1
- Guidelines
- Consider using protected objects to provide
mutually exclusive access to data. - Consider using protected objects to control or
synchronize access to data - shared by multiple tasks.
- Consider using protected objects to implement
synchronization, - such as a passive resource monitor.
- Consider encapsulating protected objects in the
private part - or body of a package.
- Consider using a protected procedure to
implement an interrupt handler. - Do not attach a protected procedure handler to
a hardware interrupt if that - interrupt has a maximum priority greater than
the ceiling priority - assigned to the handler.
- Avoid the use of global variables in entry
barriers. - Avoid the use of barrier expressions with side
effects.
38Ada 95 Quality Style Guide Section 6.1.16.1
Concurrency Options 6.1.1 Protected Objects 2
Example generic type Item is
private Maximum_Buffer_Size in
Positive package Bounded_Buffer_Package is
subtype Buffer_Index is Positive range
1..Maximum_Buffer_Size subtype
Buffer_Count is Natural range 0..Maximum_Buffer_S
ize type Buffer_Array is array
(Buffer_Index) of Item protected type
Bounded_Buffer is entry Get (X out
Item) entry Put (X in Item)
private Get_Index Buffer_Index
1 Put_Index Buffer_Index 1
Count Buffer_Count 0
Data Buffer_Array end
Bounded_Buffer end Bounded_Buffer_Package
39Ada 95 Quality Style Guide Section 6.1.16.1
Concurrency Options 6.1.1 Protected Objects 3
package body Bounded_Buffer_Package is
Example
(continued) protected body Bounded_Buffer is
entry Get (X out Item) when Count gt 0
is begin X
Data(Get_Index) Get_Index
(Get_Index mod Maximum_Buffer_Size) 1
Count Count - 1 end Get
entry Put (X in Item) when Count lt
Maximum_Buffer_Size is begin
Data(Put_Index) X Put_Index
(Put_Index mod Maximum_Buffer_Size) 1
Count Count 1 end
Put end Bounded_Buffer end
Bounded_Buffer_Package
40Ada 95 Quality Style Guide Section 6.1.16.1
Concurrency Options 6.1.1 Protected Objects 4
Rationale Protected objects are intended to
provide a "lightweight" mechanism for mutual
exclusion and data synchronization. You should
use a task only when you need to introduce
explicitly a new, concurrent thread of control
(see Guideline 6.1.2). A protected procedure is
very well suited to act as an interrupt handler
for a number of reasons they both typically have
a short bounded execution time, do not
arbitrarily block, have a limited context and
finally they both have to integrate with the
priority model. The nonblocking critical region
matches the needs of an interrupt handler, as
well as the needs of non-interrupt-level code to
synchronize with an interrupt handler. The entry
barrier construct allows an interrupt handler to
signal a normal task by changing the state of a
component of the protected object and thereby
making a barrier true. A global variable could
be changed by another task or even by a call of a
protected function. These changes will not be
acted upon promptly. Therefore, you should not
use a global variable in an entry barrier.
41Ada 95 Quality Style Guide 6.1.4 Anonymous
Task Types and Protected Types
- Guidelines
- Consider using single protected declarations
to declare unique instances of protected objects. - Rationale
- The use of anonymous protected objects of
anonymous type avoids a proliferation of
protected types that are only used once, and the
practice communicates to maintainers that there
are no other protected objects of that type. If
the need arises later to have additional
protected objects of the same type, then the work
required to convert an anonymous anonymous
protected object to a protected type is minimal. - The consistent and logical use of protected
types, contributes to understandability.
Identical protected objects can be declared using
a common protected type. Dynamically allocated
protected structures are necessary when you must
create and destroy protected objects dynamically
or when you must reference them by different
names.
Huh?
Huh?
Huh?
42Ada 95 Quality Style Guide6.1.8 Extensibility
and Concurrent Structures - 1
- Guidelines
- Carefully consider the placement of components
of protected types within a tagged type
inheritance hierarchy. - Consider using generics to provide
extensibility of data types requiring the
restrictions provided by protected objects. - Rationale
- Once a component of a protected type is added
to an inheritance hierarchy of an abstract data
type, further extensibility of that data type is
impaired. When you constrain the concurrent
behavior of a type (i.e., introduce a protected
type component), you lose the ability to modify
that behavior in subsequent derivations.
Therefore, when the need arises for a version of
an abstract data type to impose the restrictions
provided by protected objects, the opportunity
for reuse is maximized by adding the protected
objects at the leaves of the inheritance
hierarchy. - The reusability of common protected operations
(e.g., mutually exclusive read/write operations)
can be maximized by using generic implementations
of abstract data types. These generic
implementations then provide templates that can
be instantiated with data types specific to
individual applications.
Huh?
43Ada 95 Quality Style Guide6.1.8 Extensibility
and Concurrent Structures - 2
- Rationale (Continued)
- The reusability of common protected operations
(e.g., mutually exclusive read/write operations)
can be maximized by using generic implementations
of abstract data types. These generic
implementations then provide templates that can
be instantiated with data types specific to
individual applications. - Note You can address synchronization within an
inheritance hierarchy - - You can declare the root as a limited tagged
type with a component that belongs to a protected
type and give the tagged type primitive
operations that work by invoking the protected
operations of that component. - - Given a tagged type implementing an abstract
data type (perhaps resulting from several
extensions), you can declare a protected type
with a component belonging to the tagged type.
The body of each protected operation would then
invoke the corresponding operation of the
abstract data type. The protected operations
provide mutual exclusion. - - You can use a hybrid approach where you declare
a protected type with a component of some tagged
type. You then use this protected type to
implement a new root tagged type (not a
descendant of the original tagged type).
44Ada 95 Quality Style Guide 6.2.3 Attributes
'Count, 'Callable, and 'Terminated
- Guidelines
- Do not depend on the values of the task
attributes 'Callable or 'Terminated - Do not depend on attributes to avoid
Tasking_Error on an entry call. - For tasks, do not depend on the value of the
entry attribute 'Count. - Using the 'Count attribute with protected
entries is more reliable than using - the 'Count attribute with task entries.
- Rationale
- Attributes 'Callable, 'Terminated, and 'Count
are all subject to race conditions. - The value of the attribute 'Count is stable for
protected units because any change to an entry
queue is itself a protected action, which will
not occur while any other protected action is
already proceeding. Nevertheless, when you use
'Count within an entry barrier of a protected
unit, you should remember that the condition of
the barrier is evaluated both before and after
queueing a given caller.
45Ada 95 Quality Style Guide 6.2.4 Unprotected
Shared Variables
- Guidelines
- Use calls on protected subprograms or entries
to pass data between tasks - rather than unprotected shared variables.
- Do not use unprotected shared variables as a
task synchronization device. - Do not reference nonlocal variables in a guard.
- If an unprotected sharing is necessary, use the
pragma Volatile or Atomic. - Examples 2 examples of failure due to
synchronization problems - Printer Example - no synchronization or mutual
exclusion between the task that reads a command
and the one that acts on it - Vending Machine Example - Guard is a global
with no protection - Rationale
- There are many techniques for protecting and
synchronizing data access. You must program most
of them yourself to use them. It is difficult to
write a program that shares unprotected data
correctly. If it is not done correctly, the
reliability of the program suffers.
46Ada 95 Quality Style Guide 6.2.5 Selective
Accepts and Entry Calls
- Guidelines
- Consider using protected objects instead of the
rendezvous for - data-oriented synchronization.
- Rationale
- Protected objects offer an efficient means for
providing data-oriented synchronization.
Operations on protected objects incur less
execution overhead than tasks and are more
efficient for data synchronization and
communication than the rendezvous.
47Ada 95 Quality Style Guide - 7.0 Portability
7.4.7Unprotected Shared Variables and Pragmas
Atomic and Volatile
- Guidelines
- Do not use unprotected shared variables.
- Consider using protected types to provide data
synchronization. - Do not use unprotected shared variables as a
task synchronization device. - Consider using protected objects to encapsulate
shared data. - Use pragma Atomic or Volatile only when you are
forced to by run-time - system deficiencies.
- Rationale
- The rationale for this appears in Guidelines
6.1.1 and 6.2.4. - In addition, the treatment of unprotected
shared variables varies - from implementation to implementation, thereby
hindering portability.
48Ada 95 Quality Style Guide 10.6.2
(Performance) Protected Types - 1
- Guidelines
- For mutual exclusion, when measured performance
indicates, use protected - types as an alternative to tasking
rendezvous. - To implement an interrupt handler, when
performance measurement - indicates, use a protected procedure.
- Rationale
- Protected objects are meant to be much faster
than tasks used for the same purpose (see
Guideline 6.1.1). Determine the impact of using
protected objects to provide access safely to
encapsulated data in a concurrent program.
49Ada 95 Quality Style Guide 10.6.2
(Performance) Protected Types - 2
Example protected Object is
function Read return Float procedure
Write (Value in Float) private
Data Float end Object
protected body Object is function Read
return Float is begin
return Data end Read
procedure Write (Value in Float) is
begin Data Value end
Write end Object task type
Modify is end Modify
type Mod_Bunch is array (1 .. 5) of Modify
task body Modify is ...
begin -- Modify for I in 1 .. 200
loop The_Value Object.Read
Object.Write (The_Value - 0.125)
if The_Value lt -1.0E7 then
The_Value 1.0 end if
end loop end Modify ...
-- Block statement to be timed declare
Contending_Tasks array (1 .. 5) of
Modify begin null -- 5
tasks contend for access to protected data
end
See ACES V2.0, test "a9_pt_prot_access_02"
Compare with Monitor Task See ACES V2.0, test
"tk_rz_entry_access_02"
50Ada 95 Quality Style Guide 10.6.7
(Performance) Real-Time Systems Annex
- Guidelines
- For cases where both rendezvous and protected
types are inefficient, - consider the use of the Real-Time Systems
Annex (Annex D). - Rationale
- The packages Ada.Synchronous_Task_Control and
Ada.Asynchronous_Task_Control have been defined
to provide an alternative to tasking and
protected types for use in applications where a
minimal run-time is desired.
51ISO TR 15942 - Guide for the Use of the Ada
Programming Language in High Integrity Systems 1
- Guidelines
- High integrity systems traditionally do not
make use of high-level language features such as
concurrency - Recommends Concurrency Model
- - Fixed number of tasks
- - Tasks interact via use of shared data
(i.e., no rendezvous) - - Ravenscar Profile defined for high
integrity, efficient systems - Developed at 8th International Real-Time
Ada Workshop in 1997
52ISO TR 15942 - Guide for the Use of the Ada
Programming Language in High Integrity Systems 2
- Ravenscar Profile (portions pertaining to
Protected Objects only) - b. No unchecked deallocation of protected
objects - c. No dynamic allocation of protected
objects - e. Library level protected objects with no
entries - (to ensure atomic updates to shared
data) - f. Library level protected objects with a
single entry - (for invocation signalling). This entry
has a barrier consisting of a - single Boolean variable, moreover only
a single task may queue - this entry
- h. Atomic and Volatile pragmas
- j. Count attribute for protected entries
(but not within entry barriers) - m. Protected procedures as interrupt
handlers - 13 items in profile - 7 are
related to Protected Objects
53Automated Tools to Analyze Protected Objects
- ASIS Bases Tools (e.g., Ada Analyzer, AdaSTAT)
- Non-Locals in Guards
- Protected Operations With Blocking Operations
- Usage (e.g., Who uses each Protected Object)
- Verify Ravenscar profile is satisfied (AdaSTAT)
- ASIS Can Query
- Each Protected Operations Syntactic Element
54Conclusion
- Ada 95 Protected Objects provide a safe mechanism
to synchronize data and the control of resources
(devices) - Implemented with Mutual Exclusion for protected
subprograms - Implemented with Guarded Queues for protected
entries - Protected Objects need to be lean and mean
(should be of short duration) - Highly efficient compared to Ada 83
implementations - Much generic design guidance in Ada QS Guide
- Many design considerations for building complex
system - ASIS Tools provide capabilities to analyze
Protected Objects
Discussion??? Other Issues???