Real-Time Design Patterns in Modern C++

Course category
Training area
Course code
DP11-404
Duration
4 days
Course date
Price exc VAT
£2100.00

In 2011, the C++ standard unified the use of threading in Modern C++. The standard library now supplies the base building blocks required to implement a threaded software application. The library also addresses specific issues such as memory safety (atomic access is now part of the language). 

However, the use of these threading building blocks does not guarantee a reliable application. Building a safe, robust, threaded application requires that the core library features are built up on to create higher-order concurrency patterns.

High-quality software is not just about functionally correctness. It also requires a structure that ensures maintainability, flexibility and extensibility (characteristics of code with high intrinsic quality). This course teaches patterns to increase the intrinsic quality of the concurrent software. 

Increased intrinsic quality means:

  • The effect of bugs should be constrained, and locating and fixing bugs should be straightforward
  • It should require minimal effort to reconfigure the software to suit new purposes
  • Adding new functionality should not require a large-scale restructuring of existing code

These are characteristics that must be designed into the software from the ground up. It is usually prohibitively expensive to try and improve the intrinsic quality of software after the event.

Software design patterns originated from the realisation that applying the principles of software intrinsic quality to common problems yielded common solutions.

The course starts by reviewing the Modern C++ language features required to utilise the concurrency library. Next, it introduces the core library building blocks (e.g. thread, mutex, etc.). Finally, it introduces a series of real-time design patterns to support the construction of modern C++ threaded applications.

This course has been developed for C++ developers who are moving to Modern C++ in a concurrent, real-time environment.  It focuses on best-practice idioms of the language and patterns specifically formulated to solve common problems encountered in concurrent systems.

Course Objectives:

  • To understand what design patterns are and how the language of patterns can aid designers and developers to be more productive
  • To develop your understanding of concurrency and how it relates to program design
  • To understand the issues with multi-threaded programs and how patterns can help to circumvent these issues.
  • To provide practical experience of building concurrent, multi-threaded systems.

Delegates will learn:

  • Modern C++ syntax, semantics and library features
  • Idioms and patterns for building effective C++ programs
  • Real-time and concurrency design issues
  • Concurrency design patterns

Pre-requisites:

  • A strong working knowledge of C++ (Knowledge of C++11 onwards is useful, but not essential)
  • Some experience of development of multi-threaded applications is useful.
  • A working understanding of machine architectures is helpful.


Who should attend:

This course is suitable for:

  • Experienced Modern C++ programmers who are moving to a concurrent, real-time environment.
  • Experienced Modern C++ programmers who are looking to extend their design skills.
  • Experienced C++ programmers who are using earlier standards of C++ and are moving to Modern C++.

Duration:

Four days.

Course materials:

  • Delegate manual
  • Delegate workbook
  • Delegate datakey

Course workshop:

Attendees perform hands-on exercises during course practicals.  A large percentage of the course is given over to practical work. The tools used are indicative of current modern working practices in the embedded arena.

The C++ object model

  • Declaration and definition
  • Brace initialisation syntax
  • 'The One Declaration Rule' and ODR-use
  • Object scope and lifetime
  • The C++ object (memory) model

Uniform Initialization syntax

  • The difference between initialization and assignment
  • Aggregate types – structs
  • Brace elision
  • Classes
  • Non-Static Data Member Initialisers
  • Delegating constructors
  • std::initializer_list

Functions

  • Function call ABIs (Application Binary Interfaces)
  • Input, Output and Input-Output parameters
  • const correctness
  • Copy elision
  • Attributes
  • Optional return values

Type deduction

  • Automatic type deduction
  • Automatic function return-type deduction
  • Structured bindings
  • Using aliases

Constants

Literals
Const qualification
constexpr
constexpr functions
enum class
enum underlying type

Connecting objects

  • Unidirectional associations
  • Bidirectional association
  • Forward declarations
  • Composite object construction

Modularisation

  • What makes bad software?
  • Designing for intrinsic quality
  • Coupling
  • Cohesion
  • Encapsulation
  • Abstraction

The SOLID principles

  • Specialisation vs inheritance
  • The Liskov Substitution principle
  • The Single Responsibility principle
  • The Open-Closed principle
  • Abstract types
  • The Dependency Inversion principle
  • The Interface concept
  • The Interface Segregation principle

Containers

  • The STL container model
  • Dynamic containers
  • Emplacement
  • Memory management.

Iterators

  • The iterator model
  • Range-for 

Algorithms

  • The STL Algorithm model
  • Ranges and half-ranges
  • Iterator adapters
  • The Remove-erase idiom

Callable objects

  • Lambda expressions
  • The 'block-scoped function' concept
  • Generic lambdas
  • std::function

Smart pointers

  • The problem with raw pointers for memory management
  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

Threading

  • Concurrency vs parallelism
  • std::thread
  • Run policies
  • Polymorphic threads
  • Waiting for threads to finish
  • Detaching threads

Mutual exclusion

  • Race conditions
  • Mutual exclusion
  • The scope-locked idiom
  • std::lock_guard and std::unique_lock

Thread-safe APIs

  • When simple mutual exclusion is inadequate
  • Race conditions in APIs
  • Designing a thread-safe API
  • The Adapter pattern

Monitors

  • Condition variables
  • The Guarded Suspension pattern

Atomic types

  • Shared objects in multiprocessor environments
  • Why volatile is inappropriate
  • Atomic types
  • Load-acquire / Store-release barriers
  • When atomic types are inadequate

Resource pools

  • The multiple-reader, multiple-writer problem
  • The Reader-Writer Lock pattern
  • std::shared_mutex

Asynchronous messaging

  • The Communicating Sequential Processes (CSP) model
  • Asynchronous messages
  • The Asynchronous Message pattern
  • Making std::function asynchronous
  • Arguments on asynchronous messages
  • std::bind
  • Polymorphic asynchronous messages

Promises and Futures

  • The Deferred Synchronous Message Pattern
  • std::promise and std::future
  • Throwing exceptions between tasks
  • Packaged tasks
  • std::async
  • Launch policies

Synchronous messaging

  • Synchronous messaging characteristics
  • The function-call-as-synchronous-message
  • The problems with function calls between tasks
  • The Synchronous Message pattern
  • Using std::packaged_task for synchronous messages

Finite State Machines

  • Reactive Objects
  • Finite State Machines to describe behaviour
  • Switch-based implementations
  • Table-based implementations
  • The State pattern

Appendix - Anti-patterns

  • Commonly-occurring bad practices
  • The Anti-pattern philosophy
  • Common anti-patterns in systems