Skip to main content

6.4 Summary

concurrency options

  • 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.
  • Use tasks to model selected asynchronous threads of control within the problem domain.
  • Consider using tasks to define concurrent algorithms.
  • Consider using rendezvous when your application requires synchronous unbuffered communication.
  • Consider using discriminants to minimize the need for an explicit initialization operation (Rationale 1995, §9.1).
  • Consider using discriminants to control composite components of the protected objects, including setting the size of an entry family (Rationale 1995, §9.1).
  • Consider using a discriminant to set the priority of a protected object (Rationale 1995, §9.1).
  • Consider using a discriminant to identify an interrupt to a protected object (Rationale 1995, §9.1).
  • Consider declaring a task type with a discriminant to indicate (Rationale 1995, §9.6):
    • Priority, storage size, and size of entry families of individual tasks of a type
    • Data associated with a task (through an access discriminant)
  • Consider using single task declarations to declare unique instances of concurrent tasks.
  • Consider using single protected declarations to declare unique instances of protected objects.
  • Minimize dynamic creation of tasks because of the potentially high startup overhead; reuse tasks by having them wait for new work on some appropriate entry queue.
  • Do not rely on pragma Priority unless your compiler supports the Real-Time Annex (Ada Reference Manual 1995, Annex D) and priority scheduling.
  • Minimize risk of priority inversion by use of protected objects and ceiling priority.
  • Do not rely upon task priorities to achieve a particular sequence of task execution.
  • Do not depend on a particular delay being achievable (Nissen and Wallis 1984).
  • Use a delay until not a delay statement to delay until a specific time has been reached.
  • Avoid using a busy waiting loop instead of a delay.
  • 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.

communication

  • Minimize the work performed during a rendezvous .
  • Minimize the work performed in the selective accept loop of a task.
  • Consider using protected objects for data synchronization and communication.
  • Provide a handler for exception Program_Error whenever you cannot avoid a selectiveaccept statement whose alternatives can all be closed (Honeywell 1986).
  • Make systematic use of handlers for Tasking_Error.
  • Be prepared to handle exceptions during a rendezvous .
  • Consider using a when others exception handler.
  • Do not depend on the values of the task attributes 'Callable or 'Terminated (Nissen and Wallis 1984).
  • 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.
  • 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 shared variable is necessary, use the pragma Volatile or Atomic.
  • Use caution with conditional entry calls to task entries.
  • Use caution with selective accepts with else parts.
  • Do not depend upon a particular delay in timed entry calls to task entries.
  • Do not depend upon a particular delay in selective accepts with delay alternatives.
  • Consider using protected objects instead of the rendezvous for data-oriented synchronization.
  • Minimize the number of accept and select statements per task .
  • Minimize the number of accept statements per entry.

termination

  • Consider using an exception handler for a rendezvous within the main loop inside each task.
  • Do not create nonterminating tasks unintentionally.
  • Explicitly shut down tasks that depend on library packages.
  • Confirm that a task is terminated before freeing it with Ada.Unchecked_Deallocation.
  • Consider using a select statement with a terminate alternative rather than an accept statement alone.
  • Consider providing a terminate alternative for every selective accept that does not require an else part or a delay.
  • Do not declare or create a task within a user-defined Finalize procedure after the environment task has finished waiting for other tasks.
  • Avoid using the abort statement.
  • Consider using the asynchronous select statement rather than the abort statement.
  • Minimize uses of the asynchronous select statement.
  • Avoid assigning nonatomic global objects from a task or from the abortable part of an asynchronous select statement.
  • Place an exception handler for others at the end of a task body.
  • Consider having each exception handler at the end of a task body report the task's demise.
  • Do not rely on the task status to determine whether a rendezvous can be made with the task.
  • Do not call a task entry that directly or indirectly results in a call to an entry of the original calling task.
  • Avoid race conditions in setting an exit status code from the main program when using the procedure Ada.Command_Line.Set_Exit_Status.
  • In a program with multiple tasks, encapsulate, serialize, and check calls to the procedure Ada.Command_Line.Set_Exit_Status.
note

This page of the "Ada Quality and Style Guide" has been adapted from the original work at https://en.wikibooks.org/wiki/Ada_Style_Guide, which is licensed under the Creative Commons Attribution-ShareAlike License; additional terms may apply. Page not endorsed by Wikibooks or the Ada Style Guide Wikibook authors. This page is licensed under the same license as the original work.