RTC Toolkit  1.0.0
RTCTK API Contracts

Contract Documentation

General Use

The pre-defined contracts defined below have associated Doxygen macros that are meant to be used on:

  • free functions
  • classes
  • member functions

When used on a class it determines the default contract on the whole class. This can then be further refined on a member function level. For example in the class Foo the member Foo::Bar is thread-compatible, but Foo::Baz is refining the contract to be thread-safe:

/**
* My generally thread-compatible class but with exception.
*
* @thread_compatible{see @ref Foo::Baz for exception.}
*/
class Foo {
public:
Foo() = default;
/**
* Peforms bar
*/
void Bar();
/**
* Peforms baz
*
* @thread_safe{Baz is safe to call in parallel}.
*/
void Baz() const noexcept;
};

Inherited Contracts

Classes that inherit a contract from a base-class must abide by that contract. E.g. Foo below must remain thread safe as base class Base specified that contract:

/**
* @thread_safe
*/
struct Base {
virtual ~Base() {};
virtual void Foo() = 0;
};
/**
* @thread_safe
*/
struct Foo : Base {
virtual void Foo() {
// Must be thread safe
}
};
Note
It's always allowed to widen the contract. E.g. the Base mandates basic exception guarantee which is further improved with a strong exception guarantee:
/**
* @exception_basic
*/
struct Base {
virtual ~Base() {};
virtual void Foo() = 0;
};
struct Foo : Base {
/**
* @exception_strong
*/
virtual void Foo();
};

Thread Safety

Terminology

Note
The classification applies to the class, its member functions and other non-member functions, not their arguments.

Thread-safe - means that member or non-member functions are safe to call in parallel.

Thread-compatible - applies to classes as a whole and means that no external synchronization is required for parallel accesses to separate class instances or for const-only accesses on the same instance. Mixed const/non-const access must be externally synchronized.

Thread-hostile - means that parallel access is never safe. This may occur if e.g. a free function (or const member function) accesses a global shared state in a non-const fashion.

This table summarize operations that are safe in parallel for the different classifications:

Parallel operation Thread-safe Thread-compatible Thread-hostile
Const-only x x
Non-const w/ separate instances x x
Non-const w/ same instance x

See also related terminology:

Mandatory Contract Documentation

If not documented otherwise the following classification apply:

  • Classes and their member functions are thread-compatible.
  • Non-member functions are thread-safe.

Doxygen Macros

The following Doxygen macros are defined and adds a "Thread Safety" paragraph with optional commentary.

  • @thread_safe and @thread_safe{comment}.
  • @thread_compatible and @thread_compatible{comment}.
  • @thread_hostile and @thread_hostile{comment}.

The macros are used in class or function declarations:

/**
* A free function that is not thread safe.
*
* @thread_hostile{Impure function that also accesses global state.}
*/
void Foo(Arg arg);
/**
* A thread safe class.
*
* @thread_safe
*/
class Bar {
public:
Bar() = default;
};

If macro is used on the class-level it defines the behaviour for the whole class. Exceptions for individual member functions is allowed, e.g.:

Exception Safety

Terminology

The adopted terminology comes from B. Stroustrup (2000), "The C++ Programming Language" Appendix E, also summarized on cppreference.com.

The terms are summarized even further here:

  1. Nothrow exception guarantee – function never throws. This is indicated by the noexcept keyword.
  2. Strong exception guarantee – in addition to the basic guarantee, either the operation succeeds or has no effects.
  3. Basic exception guarantee – if function throws an exception, the program is in a valid state. No resources are leaked, and all objects' invariants are intact.
  4. No exception guarantee – does not specify any guaranteed behaviour. Program may be left in invalid state. This should be avoided.

Additionally there's the neutral exception guarantee that will in template contexts adopt the guarantee of the provided template parameter.

Mandatory Contract Documentation

If not documented otherwise the following classification apply:

  • Functions (member and free) satisfies the basic exception guarantee.

Doxygen Macros

The following Doxygen macros are defined and adds a "Exception Safety" paragraph with optional commentary.

  • @exception_strong and @exception_strong{comment} for strong exception guarantee.
  • @exception_basic and @exception_basic{comment} for basic exception guarantee.
  • @exception_neutral{comment} for neutral exception guarantee (comment with additional detail should be provided so there is no macro version without argument).
  • @exception_no_guarantee and @exception_no_guarantee{comment} for the no exception guarantee.

And additionally for a custom entry:

  • @exception_safety{name, comment} for non-standard exception guarantees. Comment should specify the details.

There is no macro for the nothrow exception guarantee as C++ has a noexcept specifier. If noexcept is conditional the documentation should clarify using the existing macros.