From: Michael Glassford (glassfordm_at_[hidden])
Date: 2004-07-08 09:33:32


Peter Dimov wrote:

> Eric Niebler wrote:
>
>>How about:
>>
>>if( ScopedLock l = try_lock( m ) )
>>{
>>}
>
>
> You know that I very much favor declarations in conditions, but this is a
> whole new design, one that uses moveable locks. Something like:
>
> class Mutex
> {
> public:
>
> AutoLock lock();
> AutoLock try_lock();
> AutoLock timed_lock( xtime );
> };
>
> One might argue that a lock is naturally moveable...

This does need to be addressed someday, but...

> but I think that we
> should constrain ourselves to (fixing) the current noncopyable scoped_lock
> idiom.

I agree that movable locks should wait. However, what about something
like this, which doesn't require movable locks (concept only--there are
probably errors):

    //----- locker classes -----/

    template <typename Mutex>
    class unlocked
    {
    public:

       unlocked(Mutex& m)
       : m_(m) {}

       template <typename Lock>
       operator () (Lock& l) const
       {}
    };

    template <typename Mutex>
    class locked
    {
    public:

       locked(Mutex& m)
       : m_(m) {}

       template <typename Lock>
       operator () (Lock& l) const
       {l.lock();}
    };

    template <typename Mutex>
    class try_locked
    {
    public:

       try_locked(Mutex& m)
       : m_m(m) {}

       template <typename Lock>
       operator () (Lock& l) const
       {l.try_lock();}

       Mutex m_;

    private:

       bool locked_;
    };

    template <typename Mutex>
    class timed_locked
    {
    public:

       timed_locked(Mutex& m, const xtime& t)
       : m_m(m), t_(t) {}

       template <typename Lock>
       operator () (Lock& l) const
       {l.timed_lock(t);}

       Mutex m_;

    private:

       bool t_;
    };

    //----- lock classes -----/

    class lock
    {
    public:

       template <class Locker>
       try_lock(const Locker& locker)
       : m_(locker.m_)
       {locker(*this);}
    }

    class try_lock
    {
    public:

       template <class Locker>
       try_lock(const Locker& locker)
       : m_(locker.m_)
       {locker(*this);}
    }

    class timed_lock
    {
    public:

       template <class Locker>
       try_lock(const Locker& locker)
       : m_(locker.m_)
       {locker(*this);}
    }

    //----- example -----/

    mutex m;

    lock l1 = unlocked(m);
    lock l2 = locked(m);

    try_lock l3 = unlocked(m);
    try_lock l4 = locked(m);
    if (try_lock l5 = try_locked(m)) {/*...*/}

    timed_lock l6 = unlocked(m);
    timed_lock l7 = locked(m);
    if (timed_lock l8 = try_locked(m)) {/*...*/}
    if (timed_lock l9 = timed_locked(m, get_xtime()) {/*...*/}

To select whether a lock should be locked or not at runtime, you could
add constructors to the locker classes that take a bool or enum and
redefine their operator() to lock if the constructor parameter indicated
that it should.

Mike