Our application is multithreaded—it consists of the main thread that runs the monitoring and the background worker thread. We use three global variables for their synchronization.
The touched variable is holding the timestamp that is to be periodically updated by the Worker thread. Since the timestamp is accessed by both threads, access needs to be protected. We use an m mutex for this purpose. Finally, to indicate that the worker thread has finished its job, an atomic variable, ready, is used.
The worker thread is a loop that contains artificial delays inside. The delay is calculated based on the step number, resulting in delays from 100 milliseconds to 130 milliseconds:
std::this_thread::sleep_for(
std::chrono::milliseconds(100 + (i % 4) * 10));
On each iteration, the Worker thread updates the timestamp. A lock guard is used to synchronize access to the timestamp:
{
std::lock_guard<std::mutex> l(m);
touched = std::chrono::steady_clock::now();
}
The monitoring routine runs in a loop while the Worker thread is running. On each iteration, it calculates the time interval between the current time and the last update:
std::lock_guard<std::mutex> l(m);
auto delta = now - touched;
If it is larger than the threshold, the function prints a warning message, as shown:
if (delta > threshold) {
std::cout << "Execution threshold exceeded" << std::endl;
}
In many cases, applications may invoke a recovery function to reset a peripheral device or restart the thread. We add a delay of 10 milliseconds in the monitoring loop:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
This helps us to reduce resource consumption yet achieve an acceptable reaction time. Running the application produces the following output:
We can see several warnings in the output, indicating that some iterations in the worker thread took more time than the threshold of 120 milliseconds. It is predictable since the worker function is written this way. It is important that we use a monotonic std::chrono::steady_clock function for monitoring purposes. Using the system clock could lead to the spurious invocations of the recovery function during the clock adjustments.