what is the correct behavior of pthread_mutex_destroy when destroying a locked mutex
The quoted text:
Attempting to destroy a locked mutex or a mutex that is referenced (for example, while being used in a
pthread_cond_timedwait()
orpthread_cond_wait()
) by another thread results in undefined behavior.
Should be interpreted with the "results in undefined behavior" clause distributed over the "or" conjunction. In other words:
Attempting to destroy a locked mutex results in undefined behavior.
and
Attempting to destroy a mutex that is referenced (for example, while being used in a
pthread_cond_timedwait()
orpthread_cond_wait()
) by another thread results in undefined behavior.
The second version is significant, because when waiting on the condition variable, the associated mutex lock is released by the waiting thread.
How to safely and correctly destroy a mutex in Linux using pthread_mutex_destroy?
The POSIX spec for pthread_mutex_destroy()
says:
It shall be safe to destroy an initialized mutex that is unlocked.
Which means that if thread B calls pthread_mutex_unlock()
in the else
clause of the if
statement in foo_rele()
then it's safe for thread A to call pthread_mutex_destroy()
because it can only have gotten there after thread B's pthread_mutex_unlock()
call has unlocked the mutex.
All of this is assuming that the reference counting is correct, such that some other thread cannot increment the count from 0 -> 1 after thread A has unlocked the mutex. In other words, at the point where the refcount drops to 0, there can't be another thread that might possibly call foo_hold()
.
APUE mentions this in the explanation right after the example code:
In this example, we have ignored how threads find an object before calling
foo_hold
. Even though the reference count is zero, it would be a mistake forfoo_rele
to free the object’s memory if another thread is blocked on the mutex in a call tofoo_hold
. We can avoid this problem by ensuring that the object can’t be found before freeing its memory. We’ll see how to do this in the examples that follow.
How to properly dispose of a pthread mutex?
My question is, what is the best way to handle the destruction of a mutex? Should I wait for it to be free?
You should not destroy resources while they are being used because that often leads to undefined behaviour.
The correct course of action is:
- Tell the other thread to release the resources and wait till it does, or
- Tell the other thread to terminate politely an wait till it has done so, or
- Pass the ownership of the resource to another thread and let it manage the resource's lifetime as it pleases, or
- Use shared resources, so that they stay alive while its users are still around.
How to check whether a mutex lock have been destroyed or not?
Once you destroy a a c object, the data left behind is garbage. c++ doesn't let you do this. (It does but you have to explicitly ask for it.) But you are using a c library, so you have to do everything yourself.
So you have a few options:
use std::mutex which works nicely with c++. But as such, you mutex will have the same lifetime as your containing class. (which is neates)
only use
pthread_mutex_destroy
in your destructor. Same result as above. You mutex is destroyed as you object is destroyed, which happens exactly once.use an
std::optional
to shield the mutex data if it is not initialized.
Wouldn't recommend, as it is an ugly mix of c and c++.use a bool to keep track whether you mutex is inited.
This is also tricky and ugly as it is prone to mistakes.
I cannot be more specific because i don't know the rest of the code.
Destruction of pthread mutexes and deinitialization order in C++
Since initializing with PTHREAD_MUTEX_INITIALIZER
is equivalent to calling pthread_mutex_init
, it is OK to call pthread_mutex_destroy
to destroy such a mutex.
However, calling pthread_mutex_destroy
is not required; the resources will be reclaimed by the OS at program exit. Since it is an object with a trivial destructor, it is not destroyed as part of static cleanup at program exit, and so is safe to use until the end of the program.
Related Topics
Under What Circumstances Is It Advantageous to Give an Implementation of a Pure Virtual Function
What Does ## in a #Define Mean
Access Violation Writing Location 0Xcccccccc
Gcc 7, -Wimplicit-Fallthrough Warnings, and Portable Way to Clear Them
Casting to Void* and Back to Original_Data_Type*
Copy Constructor of Derived Qt Class
What Is the Fastest Way to Compute Large Power of 2 Modulo a Number
Array[Byte] to Hbitmap or Cbitmap
Windows Named Pipe Support in Linux
Are Destructors Run When Calling Exit()
After Sending a Lot, My Send() Call Causes My Program to Stall Completely. How Is This Possible
What Happens When Calling the Destructor of a Thread Object That Has a Condition Variable Waiting
Template Metaprogramming: (Trait For) Dissecting a Specified Template into Types T<T2,T3 N,T4, ...>
Why Does Std::Map Not Have a Const Accessor
Register an Object Creator in Object Factory
C++ Error on Ms Visual Studio: "Windows Has Triggered a Breakpoint in Javaw.Exe"
Why Are Override and Final Identifiers with Special Meaning Instead of Reserved Keywords