Modern computer programs will often use multiple parallel threads of execution in order to fully utilise the performance available with modern multi-core processors. For example, in radar processing applications, one thread will manage user interface display and interactions, while other threads may handle real-time input from sensors, processing of data and output to other systems.
As of the 2011 version of the C++ standard, C++ rigidly defines the allowed interactions between threads. Modern C++ compilers take advantage of the rules around thread interactions in order to optimise compiled code. This can mean that even small transgressions of the rules around threading can result in significant unexpected behaviour, without any compiler warnings or errors. The SPx library provides tools to correctly use threads, even with legacy compilers.
The C++ rules regarding thread interaction are in many cases much stricter than the requirements imposed by the underlying hardware. For example, the x86-64 processor architecture guarantees that concurrent reads and writes to a 32-bit integer are atomic and well-defined. The C++ thread model, however, does not. This means that even a single write to a 32-bit integer from one thread and a single read from the same 32-bit integer in another thread must have some sort of synchronisation in order to be well-defined. Failure to do so will result in a data race, which in C++ is undefined behaviour.
Figure 1 demonstrates a very simple data race where one thread is reading from a shared integer variable, while another thread writes to the same variable – this results in undefined behaviour.
The two main types of synchronisation that prevent data races are mutex protection and the use of special atomic variables. Mutex protection allows all accesses to a variable or set of data to be protected by a shared lock called a mutex. By ensuring that the mutex is locked while accessing the variable or data, concurrent access by multiple threads is avoided. If a thread, A, attempts to acquire the lock on the mutex while another thread, B already has the mutex locked, thread A automatically waits until thread B has finished before accessing the shared data. C++ provides the std::mutex type that may be locked around any accesses to shared variables to avoid concurrent access. Figure 2 demonstrates how the undefined behaviour from Figure 1 may be fixed by the use of a mutex...
Subscribe to continue reading this article, it's free.
Free access to Engineering Insights, authored by our industry leading experts.
You will also receive the Cambridge Pixel newsletter which includes the latest Engineering Insights releases.
Fill in the form below and you will be sent an Instant Access link.