Boost logo

Boost :

Subject: Re: [boost] [thread] synchronized_value: value and move semantics
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2013-06-27 14:45:27


Le 26/06/13 19:55, Andrey Semashev a écrit :
> On Wednesday 26 June 2013 08:55:33 Vicente Botet wrote:
>> Andrey Semashev-2 wrote
>>
>>> 1. Why are there strict_lock_ptr and unique_lock_ptr?
>> These a locking pointers that lock at construction and unlock at
>> destruction. Both classes have pointer semantics.
>>
>>> What are the
>>> differences
>> strict_lock_ptr cannot be unlocked (something like lock_guard) and
>> unique_lock_ptr is a model of Lockable so it provides the lock/unlock
>> functions as unique_lock.
>>
>>> and why we can't have one such ptr (presumably,
>>> unique_lock_ptr)?
>> Sorry I don't understand.
> What I mean is that there is no apparent advantage of using strict_lock_ptr
> instead of unique_lock_ptr. strict_lock_ptr is a bit more limited than
> unique_lock_ptr but it doesn't provide anything in return. Yet it complicates
> synchronized_value interface and adds confusion (when should I call
> synchronize() and when unique_synchronize()?). So I don't see the point in
> having strict_lock_ptr.
>
> Note that although there exist both lock_guard and unique_lock, the former is
> more efficient when you don't need movability and optional locking of the
> latter. This is not the case with strict_lock_ptr and unique_lock_ptr since
> both use unique_lock internally.
The current implementation uses unique_lock, but I plan to use a
specific implementation that is more efficient.
>
>>> 3. Am I correct that having strict_lock_ptr/unique_lock_ptr acquired by
>>> calling synchronize() will not deadlock with operator-> when a
>>> non-recursive mutex is used?
>> To which operator-> are you referring to? the one from
>> strict_lock_ptr/unique_lock_ptr?
>> synchronize() is used to lock at block scope. The user must use the obtained
>> locking pointer to access to the functions of the synchronized value using
>> the operator->.
>> I'm not sure to understand what could be the issue.
> I was referring to synchronized_value<>::operator->. What I mean is this:
>
> synchronized_value< foo, mutex > sync_foo;
> auto locked = sync_foo.synchronize();
> sync_foo->bar(); // deadlock??
>
> If I use a non-recursive mutex, like the above, and store the strict_lock_ptr
> or unique_lock_ptr in locked, will I be able to call bar()? The operator-> is
> supposed to create a new strict_lock_ptr, which is supposed to attempt to lock
> the mutex again, isn't it?
Right.
> Perhaps, it would be better to restrict the number of lock_ptrs for a single
> synchronized_value that can exist concurrently to just one? Then the above
> code would be invalid and should be written as follows:
>
> synchronized_value< foo, mutex > sync_foo;
> auto locked = sync_foo.synchronize();
> // sync_foo->bar(); // <-- assertion failure or exception
> locked->bar(); // ok
>
>
You could get the same behavior with a mutex that checks if the current
thread is locking the mutex alteady. Boost.Thread contains a
boost::testable_mutex (that I have not documented yet) that maybe can be
updated to assert in this case. So the following would behave as you are
requesting.

   synchronized_value< foo, testable_mutex > sync_foo;
   auto locked = sync_foo.synchronize();
   // sync_foo->bar(); // <-- assertion failure or exception
   locked->bar(); // ok

Best,
Vicente


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