Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2004-07-14 10:45:00


Howard Hinnant wrote:
> On Jul 14, 2004, at 6:27 AM, Alexander Terekhov wrote:
>
>> It is a philosophical issue, not technical.
>
> Thanks for your comments.
>
> Speaking philosophically ... just wondering out loud, not trying to
> solve anything, I wonder if this doesn't boil down to an object
> oriented view vs a functional view. Because the few times I've felt
> the need for a recursive mutex is when I had an object, which contained
> a single mutex, which had several public member functions that just
> happened to call each other as an implementation detail. Something
> like:
>
> class A
> {
> public:
> void foo1(); // calls foo2 and foo3 under the covers
> void foo2();
> void foo3();
> private:
> mutex mut_;
> };

Yep, classic. ;-)

The solution is, of course:

class A
{
public:

    void foo1()
    {
        scoped_lock<> lock(mut_);
        foo1_impl();
    }

    void foo2()
    {
        scoped_lock<> lock(mut_);
        foo2_impl();
    }

    void foo3()
    {
        scoped_lock<> lock(mut_);
        foo3_impl();
    }

private:

    void foo1_impl(); // calls foo2_impl & foo3_impl
    void foo2_impl();
    void foo3_impl();

    mutex mut_;
};

I have a recursive_mutex use case that's not as trivial, though. Imagine a
mutex pool with a fixed size N that protects an unbounded set of objects
(hashing the object address mod N to determine the mutex to lock). Now when
you need to protect two objects at the same time, due to the probability of
a collision the mutexes need to be recursive. It's still not watertight,
because if the two locks are removed from each other, this seems like a
deadlock invitation; and if the two locks are made at the same time, the
recursive lock can be avoided locally.

[...]

> Admittedly, I've never felt the need to wait on a recursively locked
> mutex, but it seems like it would be reasonable for foo2() in the
> above example to do so, whether or not it had been called from an
> external client, or from foo1().

That's exactly the problem. If foo2 waits, it will release not only its own
lock, but also foo1's lock, which may not be safe to release (i.e. foo1 may
have left the object in a broken state, expecting that nobody can see it
since it holds a lock.) It's all in Butenhof's posts.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk