Boost logo

Boost :

From: Batov, Vladimir (Vladimir.Batov_at_[hidden])
Date: 2004-06-28 20:55:13


Guys,

Could we please resist complicating interfaces when we do not have to? I
personally consider an additional blocking parameter for something like
try_lock excessive because it distorts try_lock into becoming
scoped_lock. Let's keep different concepts different. Blocking in
try_lock is an oxymoron -- try_lock cannot block because it is "try".

The basic usages (covering about 80%) are:

scoped_lock l(m); // Block until it locks.
scoped_try_lock l(m); // Try (!) to lock. I'll check the result.
scoped_timed_lock l(m, time); // Block until it locks or time runs out.
I'll check the result.

Simple and clean. The only functionality that I can see beyond that is
when I have to only declare a lock but apply it later. Like:

Void
Foo()
{
        scoped_lock l(m, do_not_lock);

        if (something)
        {
                l.lock(); // Can't declare here.
                ...
        }
}

For that purpose we'll need something like

scoped_lock(mutex&, nolock_t);

That's it. Isn't it?

Alternatively we might consider making timed_lock our basic lock as
scoped_lock and try_lock are merely border-cases (time=infinite and
time=0 respectively). Then, scoped_lock and try_lock would be real
refinements (convenience interfaces) of that general concept.

V.

Christopher Currie wrote:
> Michael Glassford wrote:
>
> > To address these problems, I would like to redefine the lock concept

> > constructors as follows (changes indicated with "^"):
> >
> > Definitions
> > -----------
> > L: lock type
> > l: lock variable (type L)
> > m: mutex variable (appropriate Mutex type)
> > s: initial lock state (enum type {NO_LOCK=0, LOCK=1})
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > b: block? (enum type blocking_state {NON_BLOCKING=0, BLOCKING=1})
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >
> > Lock Concept
> > ------------
> > L l(m,s) //Blocking lock if s
> > L l(m) //Blocking lock
> >
> >
> > TryLock Concept
> > ---------------
> > L l(m,s,b) //Lock if s; blocking if b
> > ^ ^^^^^^^^^^^^^
> > L l(m,b) //Lock; blocking if b
> > ^ ^^^^^^^^^^^^^
> >
> > TimedLock Concept
> > -----------------
> > L l(m,s,b) //Lock if s; blocking if b
> > ^ ^^^^^^^^^^^^^
> > L l(m,t) //Blocking lock, failing if not obtained by time t
> >
>
> I like this proposal, if for no other reason than the move to enums
> makes the arguments clearer. A couple of points:

Yes, I like LOCK and NO_LOCK better than true and false for the same
reason.

> TryLock: What would be the semantics of l(m, NO_LOCK, b)? In other
> words, if you're not going to lock on construction, why specify a
> blocking policy?

The only reason is so that if you write l(m, LOCK, ...) you could also
specify the blocking parameter. An expansion of Vladimir Batov's of
using structs rather than enums could help here:

struct nolock_t {};
nolock_t nolock;

struct lock_t {};
lock_t lock;

class TryLock
{
TryLock(TryMutex m, no_lock_t s)
{...}

TryLock(TryMutex m, lock_t s, blocking_t b)
{...}
}

> L l(m, b) and L l(m, s) seem to cover the two
> scenarios: either I don't want to lock, or I do and I need to specify

> the blocking policy.
>
> TimedLock: I'm not sure I follow the reasons why TimedMutex refines
> TryMutex. (This is a comment on the original design, not your
specific
> changed, but bear with me.) I think a timeout of zero seconds
achieves
> the same goal, even if TimedLock/TimedMutex don't implement the same
> operations.
> So I don't think that TimedLock needs a constructor that
> takes a blocking argument, and ultimately I think
TimedLock/TimedMutex
> should refine Mutex/Lock, and not TryMutex/TryLock.

> Also, the current implementation of TimedLock doesn't support a
single
> argument constructor, even though it is supposedly a refinement of
> TryLock, which does. I'd like to see TimedLock implemented in such a
way
> that I could use it as if it were a simple Lock, which I currently
cannot.
> In summary, this is what I'd like to see:
>
> Lock Concept
> ---------------
> L l(m) //Blocking lock
> L l(m,s) //Blocking lock if s
>
> TryLock Concept
> ---------------
> As Lock, *plus:*
> L l(m,b) //Lock; blocking if b
>
> TimedLock Concept
> -----------------
> As Lock (not TryLock), *plus:*
> L l(m,t) //Blocking lock, failing if not obtained by time t
> //If t == 0, acts as TryLock.
>

As I said in another post, I'll think about this some more. Thanks for
taking the time to comment.

Mike


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