Walter is right about transitive readonly - here's the alternative

Sean Kelly sean at f4.ca
Thu Sep 13 16:50:23 PDT 2007


Bruce Adams wrote:
> Sean Kelly Wrote:
> 
>> Janice Caron wrote:
>>> On 9/13/07, Sean Kelly <sean at f4.ca> wrote:
>>>>> Upgrading just isn't possible in any case - not even in /theory/, let
>>>>> alone in a given implementation.
>>>> I'm sure it could be done
>>> It certainly can't be done atomically...
>>>
>>> Threads 1 and 2 both successfully obtain a read lock.
>>> Thread 1 attempts to upgrade to a write lock. Since thread 2 has a
>>> read lock, it waits.
>>> Thread 2 attempts to upgrade to a write lock. Since thread 1 has a
>>> read lock, it waits.
>>> Deadlock.
>>>
>>>
>>>> (in fact, POSIX has this feature)
>>> I wonder how. If it's implemented as release the read lock followed by
>>> obtain a write lock, then the caller must beware that another thread
>>> may have written /during/ the upgrade.
>> If I had to guess, I'd say that the upgrade works by ensuring that 
>> upgrading readers are given precedence when acquiring a write lock, so 
>> there is no risk of an external writer acquiring the lock if there are 
>> any readers in the process of upgrading.  Since the POSIX library is 
>> already explicitly managing the list of waiters rather than relying on 
>> someone else's mutex/condvar/semaphore/whatever to do so, the additional 
>> logic may not be a terrible burden.
> 
> Posix provides this feature for advisory FILE lockiing and not for looking areas of memory though there is some parallel (especially if you use memory mapped files). These locks are per process and mediated by the OS rather than per thread. The fcntl call can fail or the process can be told to wait forever, inviting deadlock. The POSIX API is very low level and typically needs to be wrapped up to make it more user friendly.

Really?  Where do pthread_rwlock_* fall in this?  I had thought htese 
routines were for thread synchronization.

Regarding pthread_rwlock_*, it turns out I was wrong about the upgrading 
  however.  The approach is to call pthread_rwlock_trywrlock, and this 
will only succeed if no other threads hold either a read or write lock 
but the caller.  This is far more limited than I had remembered.

> I don't think going POSIX is the answer in this case.

Me either, frankly.  Tango's ReadWriteLock doesn't even use the 
pthread_rwlock routines.  I mostly mentioned them because I thought they 
were an example of a read/write lock implementation that supported 
upgrading.

> However, I do believe the ability to try a lock or specify a timeout is important. Janice's solution though elegant does not provide support for this. At minimum a "trylock / islock" is required on which the rest can be built.

I /really/ tried to come up with a syntax for integrating trylocks with 
'synchronized', but doing so would have required compiler support and I 
couldn't find a syntax that seemed to fit.  Tango does have tryLock 
calls in its mutex classes however, and some of the primitives allow 
timeouts as well.  The general syntax is:

     auto m = new Mutex;
     if( m.tryLock() ) {
         scope(exit) m.unlock();
         ...
     }

An in-language version would have to be something like:

     synchronized( m.tryLock ) {

     }
     else {

     }


Sean



More information about the Digitalmars-d mailing list