C++0x thread library or Boost.thread define non-member variadic template function that lock all lock avoiding dead lock.
template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
While this function avoid help to deadlock, the standard do not includes the associated scoped lock to write exception safe code.
{
std::lock(l1,l2);
// do some thing
// unlock li l2 exception safe
}
That means that we need to use other mechanism as try-catch block to make exception safe code or define our own scoped lock on multiple mutexes ourselves or even do that
{
std::lock(l1,l2);
std::unique_lock lk1(l1, std::adopted);
std::unique_lock lk2(l2, std::adopted);
// do some thing
// unlock li l2 on destruction of lk1 lk2
}
Why the standard doesn't includes a scoped lock on multiple mutexes of the same type, as for example
{
std::array_unique_lock<std::mutex> lk(l1,l2);
// do some thing
// unlock l1 l2 on destruction of lk
}
or tuples of mutexes
{
std::tuple_unique_lock<std::mutex, std::recursive_mutex> lk(l1,l2);
// do some thing
// unlock l1 l2 on destruction of lk
}
Is there something wrong on the design?
Updated: description from the standard
template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
Requires: Each template parameter type shall meet the Mutex requirements, except that a call to try_- lock() may throw an exception. [ Note: The unique_lock class template meets these requirements when suitably instantiated. —end note ]
Effects: All arguments are locked via a sequence of calls to lock(), try_lock(), or unlock() on each argument. The sequence of calls shall not result in deadlock, but is otherwise unspecified. [ Note: A deadlock avoidance algorithm such as try-and-back-off must be used, but the specific algorithm is not specified to avoid over-constraining implementations. —end note ] If a call to lock() or try_lock() throws an exception, unlock() shall be called for any argument that had been locked by a call to lock() or try_lock().
I have accept the answer. I understand that the main reason is because there is no enough time to make the C++0x Thread library better. I hope that TR2 will include much more things.
Mutexes are used to prevent multiple threads from causing a data race by accessing the same shared resource at the same time. Sometimes, when locking mutexes, multiple threads hold each other's lock, and the program consequently deadlocks.
First introduced in the 2017 standard, the scoped lock is a mutex wrapper which obtains access to (locks) the provided mutex, and ensures it is unlocked when the scoped lock goes out of scope. It differs from a lock guard in that it is a wrapper for not one, but multiple mutexes.
I think that by providing defer_lock_t (and adopt_lock_t) the expectation is that usage will be like your second example, or probably more like:
std::unqiue_lock ul1(l1, std::deferred);
std::unique_lock ul2(l2, std::deferred);
std::lock(ul1, ul2);
This is exception safe and all that good stuff.
I certainly can't pretend to know the minds of the designers, but my guess is they are making an effort to provide a minimal set of portable, safe, primitives. A scoped multiple lock type is just so much icing, and it's icing that if in the standard needs to be specified and designed, or in boost.thread, icing that needs to be implemented (and of course ultimately the standard has to be concerned about implementation too, look what happened with export).
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