Destroy std::mutex referenced but not owned by std::unique_lock?
Is it correct to destroy a mutex which is referenced but not owned by an unique_lock as in this code?
{
std::unique_ptr<std::mutex> mutex = std::make_unique<std::mutex>();
std::unique_lock<std::mutex> lock(*mutex);
lock.unlock();
mutex.reset();
} // Here lock is destroyed while holding an invalid reference to *mutex
// but not having a lock on any mutex at all.
The example is somewhat convoluted and for this simple case it would be easier to not lock.unlock();mutex.reset()
and let the destructors do their work. But there are other situations where being able to do this might come handy.
It can be read in std::unique_lock::~unique_lock that :
Destroys the lock. If *this has an associated mutex and has acquired ownership of it, the mutex is unlocked.
Which leads me to believe that if the unique_lock no longer has ownership of the mutex the mutex is not unlocked so the no longer valid reference the mutex is not used in the destructor.
1 answer
No, such an operation is not safe. The documentation of std::unique_lock
in the standard states that it's UB for the mutex do be destroyed while the lock still has a pointer to it.
However, there is a way to dissociate the mutex from the lock: calling release
on the lock. That resets the lock's internal mutex pointer to null. So the code would be valid like this:
{
std::unique_ptr<std::mutex> mutex = std::make_unique<std::mutex>();
std::unique_lock<std::mutex> lock(*mutex);
lock.unlock();
lock.release();
mutex.reset();
}
Here are the relevant standard quotes from C++2a (N4680) 32.5.4.3. [thread.lock.unique] (pm
is an exposition-only pointer to the mutex associated with the lock):
32.5.4.3/1 The behavior of a program is undefined if the contained pointer
pm
is not null and the lockable object pointed to bypm
does not exist for the entire remaining lifetime (6.7.3) of theunique_lock
object.
32.5.4.3.3
mutex_type* release() noexcept;
2 Returns: The previous value of
pm
.
0 comments