Assuming
std::
mutexes and condition variablesis it guaranteed that operating on the different types of std::
mutexes and condition variables (other than on constructing them) does not throw any exceptions (especially of type std::system_error
)?
For example, in case of methods like:
void MyClass::setVariable() {
std::lock_guard<std::mutex> const guard(m_mutex);
m_var = 42; // m_var is of type int
m_conditionVariable.notify_all();
}
void MyClass::waitVariable() {
std::unique_lock<std::mutex> lock(m_mutex);
m_conditionVariable.wait(lock, [this]() noexcept { return m_var == 42; });
}
Is it safe to assume noexcept
or should one write some try-catch blocks around the callsites? Or are there any caveats?
Please consider all types of mutexes and condition variables in C++11, C++14 and later.
The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until another thread both modifies a shared variable (the condition), and notifies the condition_variable . The thread that intends to modify the shared variable has to.
While mutex implement synchronization by controlling thread access to data, condition variables allow threads to synchronize based upon the actual value of data. Without condition variables, the programmer would need to have threads continually polling (possibly in a critical section), to check if the condition is met.
look up how a unique_lock() behaves. @Prab, just to give the explanation: unique_lock() is automatically released when the destructor is called meaning it is exception safe and that it automatically unlocks when you leave scope.
Condition variables are used to wait until a particular condition predicate becomes true. This condition predicate is set by another thread, usually the one that signals the condition. A condition predicate must be protected by a mutex.
Short answer: No (sorry)
Any of these operations will throw std::system_error
if the underlying synchronisation object fails to perform its operation.
This is because correct operation of synchronisation primitives depends on:
available system resources.
some other part of the program not invalidating the primitive
Although in fairness, if (1) is happening it's probably time to redesign the application or run it on a less-loaded machine.
And if (2) is happening, the program is not logically consistent.
That being said,
or should one write some try-catch blocks around the callsites?
Also no.
You should write try/catch blocks under the following conditions:
Where the program is in a position to do something useful about the error condition (such as repairing it or asking the user if he wants to try again)
You would like to add some information to the error and re-throw it in order to provide a diagnostic breadcrumb trail (nested exceptions, for example)
You wish to log the failure and carry on.
Otherwise, the whole point of c++ exception handling is that you allow RAII to take care of resource reacquisition and allow the exception to flow up the call stack until is finds a handler that wants to handle it.
example of creating a breadcrumb trail:
void wait_for_object()
try
{
_x.wait(); // let's say it throws a system_error on a loaded system
}
catch(...)
{
std::throw_with_nested(std::runtime_error(__func__));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With