The vulnerability as described in ISO IEC 24772-1 6.62 applies to C++.
For concurrent entities created using the C library, apply the avoidance mechanisms documented in ISO IEC TR 24772-3 clause 6.62.
C++ standard threads
Within C++ standard thread concurrency, the vulnerability as specified in ISO/IEC 24772-1 clause 6.62 can arise as follows: - as part of the termination of the complete program resulting from an explicit call to a program-terminating function in any thread in the program or an implicit call on std::terminate, for example, - as a result of an unhandled exception in any thread function when using thread
or jthread
- as a result of an unhandled exception in any thread function when using C++ parallel algorithms - as a result of faulty inter-thread asynchronous communications that results in unplanned termination of a communicating thread.
Errors relating to improper shutdown and cleanup are addressed in 6.36 Unhandled errors and exceptions(??) If non-standard C++ concurrency is used, the vulnerability and avoidance mechanisms are as specified in ISO/IEC 24772-1 and ISO/IEC 24772-3.
(see https://en.cppreference.com/w/cpp/error/terminate for more termination conditions)
Joining a thread causes the joining thread to await the joined thread’s termination before continuing. Useful for executing in parallel and then proceeding after the dispatched work is complete, but does not notify the joining task if the termination was premature.
C++ 2020 provides callbacks in the form of stop_callback to notify the setting thread when a thread of interest has been terminated. It also provides stop_token for a thread to query it is being instructed to terminate. (should go in 6.60 if not there already).
The terminating thread can pass back whatever is programmed back to the `join’ function, which can include notice of premature termination, for example by returning a pointer to the handled exception that identifies the error that caused premature termination.
The semantics of C++ is that all children of the main program will prematurely terminate if the main program terminates and final results from such threads will not be delivered . It is necessary to join the main program to all its children to ensure that children are not silently terminated prematurely.
Premature termination of C++ Tasks
Tasks can abort
or terminate
or cancelled
(last one - by the scheduler) but these affect the whole program containing the thread. Therefore, the only way for a task to terminate is to receive a terminate request and transfer to the end of its code where the parent that initiated it will be waiting at the future.
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Use the avoidance mechanisms of ISO/IEC 24772-1 clause 6.63.5.
Use low-level operating system primitives or other APIs where available to check that a required thread is still active.
Prohibit explicit or implicit calls to program-terminating functions whenever active threads are executing.
Check and obey the result of stop_token.stop_requested()
periodically (see 6.60 Concurrency - Directed termination [CGT])
Return some indication of conditions resulting in premature termination
Ensure that the main program joins all created threads that need to complete normally, such as by using the std::jthread type.