Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-07-14 10:09:42


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_;
};

All three functions lock the mutex to synchronize access so A can
maintain its invariant. But foo1() is an especially complicated
operation and to help it do it's job also calls foo2() and foo3() under
the covers. foo1() can't afford to just let foo2() and foo3() handle
the locking because it also breaks invariants within it's own body
and/or must execute foo2() and foo3() atomically. foo1 may restore
invariants before calling foo2 and foo3, or foo2 and foo3 may be smart
enough to deal with the state in which foo1 calls them (just depends on
the application).

So although there are non-recursive ways to solve this problem, simply
allowing mut_ to be locked recursively is convenient. The alternative
is write a private function that might look like:

    void do_foo(int parm);

where parm indicates whether you need to do just 2, just 3, or both 2
and 3, and locks accordingly. Now foo1, foo2 and foo3 can all forward
to do_foo without locking at the top level. The more interdependent
foo's you have though, the more convenient the recursive approach
looks.

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(). foo1() could tell foo2() that it had been
called from foo1() so that foo2() would know to do an extra unlock/lock
before/after the wait. But with many foo's that solution could get as
complicated, or even more so, than the non-recursive do_foo() approach.

<sigh>

Hope I never feel the need to wait on a recursive mutex! :-)

-Howard


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