Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-07-23 13:10:32


On Jul 22, 2004, at 8:54 PM, Howard Hinnant wrote:

> On Jul 22, 2004, at 4:52 PM, Bronek Kozicki wrote:
>
>> Howard Hinnant wrote:
>>
>>>> * I do not quite like
>>>> "write_lock(try_rvalue_ref<upgradable_read_lock<mutex_type> > r);"
>>>> (neither
>>>> "exclusive_lock(try_rvalue_ref<upgradable_shared_lock<mutex_type> >
>>>> r)" ). It seems inconsistent with rest of interface. What about
>>>> "write_lock (rvalue_ref<upgradable_read_lock<mutex_type> > r,
>>>> blocking_enum block_it);" ?
>>> My problem is that this syntax does not generalize to the
>>> try-move-from-upgradable_lock-assignment:
>>> upgradable_lock ul(m);
>>> scoped_lock sl (try_move(ul));
>>> sl = try_move(ul);
>>> I really want the try-to-upgrade syntax to be consistent between
>>> copy ctor and assignment forms. The consistency makes the interface
>>> easier to learn.
>>
>> I'm little nervous seeing "try_move". If move semantics (the one you
>> proposed in N1377) gets into language, "move" can be replaced with
>> simple move-constructor, while "try_move" cannot.
>
> Actually N1377 suggests a move helper function:
>
> template <class T>
> inline
> T&&
> move(T&& x)
> {
> return static_cast<T&&>(x);
> }
>
> And N1377 got it slightly wrong. It should really look like:
>
> template <class T>
> inline
> typename remove_reference<T>::type&&
> move(T&& x)
> {
> return x;
> }
>
> If we introduce "try_move" it could be a similarly simple helper which
> just returns an auto_ptr-ref-like object tagged with the "try"
> information. Not that I'm 100% dead set on try_move, I'm not.

I've been thinking more about Bronek's nervousness with "try_move".
I've just thought of alternative syntax. I'm not sure yet whether I
like it or not. But I'm putting it out there so that it gets more eyes
than just my own (which are badly overworked at the moment)...

Below, allow for the pseudo code notation:

scoped_lock = move(scoped_lock);

To mean that given:

scoped_lock<Mutex> lock1(mut, defer_lock);
scoped_lock<Mutex> lock2(mut);

you can do:

lock1 = move(lock1);

We currently have (just discussing assignment forms below):

scoped_lock = move(scoped_lock);
scoped_lock = move(upgradable_lock); // 1
scoped_lock = try_move(upgradable_lock); // 2

sharable_lock = sharable_lock;
sharable_lock = upgradable_lock;
sharable_lock = move(scoped_lock);

upgradable_lock = sharable_lock;
upgradable_lock = move(upgradable_lock);
upgradable_lock = move(scoped_lock);

Those forms not using try_move or move take a const& on the rhs, and
never block.

Those forms using move on the rhs require the rhs to be an rvalue (or
cast with move), and never block except for 1, which can block.

The form taking try_move is a try-lock form of 1 (and thus can not
block).

Possible alternative syntax:

scoped_lock = move(scoped_lock);
scoped_lock |= move(upgradable_lock); // 1
scoped_lock <<= move(upgradable_lock); // 2

sharable_lock = sharable_lock;
sharable_lock = upgradable_lock;
sharable_lock = move(scoped_lock);

upgradable_lock = sharable_lock;
upgradable_lock = move(upgradable_lock);
upgradable_lock = move(scoped_lock);

try_move now does not exist. All operator= indicate a non-blocking
operation. The one operator|= indicates a blocking operation. And
operator<<= indicates a try-lock operation. The move on the rhs
indicates whether or not an rvalue is required there.

Specific upgradable_lock -> scoped_lock example:

upgradable_lock ul(mut);
scoped_lock sl(mut, defer_lock);
...
sl = move(ul); // compile-time error, invalid operation
sl |= move(ul); // Upgrades, blocking if necessary
sl <<= move(ul); // Tries to upgrade without blocking

On the constructor side, this could look like:

upgradable_lock ul(mut);
scoped_lock sl(ul); // block, we have this in the current spec
scoped_lock sl(ul, try_lock); // proposed to replace sl(try_move(ul))

Thoughts?

-Howard


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