|
Boost : |
Subject: [boost] Correct Mutext Destroy Behaviour, Pthreads and Boost
From: Robert Bell (skyoyster_at_[hidden])
Date: 2015-06-01 15:08:23
If an object is implemented to support reference counting, and has an internal raw pthread mutex, the open group is pretty clear in the pthread_mutex_destroy doc on what different implementations must ensure (http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_destroy.html).
Note the following statement at the bottom:
"A mutex can be destroyed immediately after it is unlocked. For example, consider the following code:"
obj_done(struct obj *op)
{
pthread_mutex_lock(&op->om);
if (--op->refcnt == 0) {
pthread_mutex_unlock(&op->om);
(A) pthread_mutex_destroy(&op->om);
(B) free(op);
} else
(C) pthread_mutex_unlock(&op->om);
}
In this case obj is reference counted and obj_done() is called whenever a reference to the object is dropped. Implementations are required to allow an object to be destroyed and freed and potentially unmapped (for example, lines A and B) immediately after the object is unlocked (line C)."
On moving some of my underlying libraries to Boost, I took a look at Boost's Mutex object. The implementation of the Mutex object's destructor call does:
~mutex()
{
int const res = posix::pthread_mutex_destroy(&m);
boost::ignore_unused(res);
BOOST_ASSERT(!res);
}
My question centres on whether Boost's implementation violates the open group's requirement. The calls to posix::pthread_mutex_destroy (Boost's wrapper), usually perform a straight-through call to ::pthread_mutex_destroy, but it occurs inside the destructor, and so does this call occur "immediately after" an unlock by the group's definition?
In straight pthreads, if I want to make sure I can rely on various implementations of the standard, I can simply do exactly what the open group says, unlock, and the next line destroy. But in the case of Boost, is it safe to do something like:
mutex->unlock();
delete mutex_;
One thing I did note of interest is that Apple's implementation seems to lock the mutex from within the destroy call, which is curious:
int
pthread_mutex_destroy(pthread_mutex_t *mutex)
{
int res;
LOCK(mutex->lock);
if (mutex->sig == _PTHREAD_MUTEX_SIG)
{
if (mutex->owner == (pthread_t)NULL &&
mutex->busy == (pthread_cond_t *)NULL)
{
mutex->sig = _PTHREAD_NO_SIG;
res = ESUCCESS;
}
else
res = EBUSY;
}
else
res = EINVAL;
UNLOCK(mutex->lock);
return (res);
}
There seems, generally, to be a good deal of confusion surrounding when it is safe to destroy the resources associated with a mutex, and most people offer widely inaccurate comments based largely on opinion. My question points to whether code adjacency is a requirement of correct behaviour in some implementations, and if not, why not?
If I have missed an obvious explanation somewhere, my apologies. I read through the different patterns of Boost threading listed in the documentation, but was not convinced the question was addressed.
Thanks in advanceâ¦
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk