Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception handling for <mutex> and <condition_variable>

Assuming

  1. no undefined behaviour occurs,
  2. no deadlocks occur,
  3. mutexes are locked and unlocked in the correct order by the correct threads the correct number of times,
  4. non-recursive mutexes are not locked multiple times,
  5. locking recursive mutexes does not exceed the maximum level of ownership,
  6. no predicates passed to condition variables throw, and
  7. only clocks, time points, and durations provided by the standard library are used with the std:: mutexes and condition variables

is 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.

like image 592
jotik Avatar asked May 13 '16 08:05

jotik


People also ask

What is Condition_variable?

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.

What's the difference between mutex and condition variable?

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.

Does Unique_lock automatically unlock?

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.

Does condition variable need mutex?

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.


1 Answers

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:

  1. available system resources.

  2. 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:

  1. 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)

  2. 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)

  3. 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__));
}
like image 190
Richard Hodges Avatar answered Oct 14 '22 16:10

Richard Hodges