Thank you for the refs and pseudocode!

Somehow I imagined this would be simpler... A proposal for Mutex.TryLock() 
was turned aside years ago because it's trivial to implement with CAS. But 
they didn't consider RWMutex.TryRLock().

https://github.com/golang/go/issues/6123

@ianlancetaylor, is this worth a new proposal?


On Tuesday, December 3, 2019 at 7:52:54 PM UTC-8, robert engels wrote:
>
> You actually only need a cas and a condition variable (technically the 
> condition in Go requires a backing lock, but if you have wait/notify it 
> isn’t needed).
>
> You can read this 
> https://code.woboq.org/userspace/glibc/nptl/pthread_rwlock_common.c.html
>  and/or https://6826.csail.mit.edu/2019/papers/HO17.pdf for the general 
> idea.
>
> Essentially, you use some bits of the ‘atomic value’ to encode phases 
> (waiting for write lock, holding write lock, reader bits) - and use the 
> cond variable to block the writers (or readers for that matter) and loop 
> and retry the cas.
>
> The following is simplified since it isn’t “fair”, but you can add another 
> bit for “writer waiting” to accomplish this. Also, the ‘condition’ must be 
> a ‘flag’ so that a signal() with no waiters is satisfied by the next wait()
>
> bits 0 - 30 number of readers
> bits 31 writer has lock
>
> WRITER = 1<<31
> read() is the atomic read of v
>
> pseudo code
>
> try_lock() {
>   for {
>   v = read()
>     if v has writer {
>               return WOULD_BLOCK
>           }
>           if(cas(v,v + 1 reader)) {
>               return OK
>           } else {
>              // loop and try again
>          }
>   }
> }
>
> runlock() {
>    for{
>       v = read()
>       if(cas(v,v -1 reader)) {
>          cond.signal() // can be optimized to not always do this, i.e. 
> only when readers is 0
>          return
>       } else {
>          // loop and try again
>       }
>   }
> }
>
> wlock() {
>    for {
>       v = read()
>       if v !=0 { 
>          cond.wait()
>      }
>      else {
>         if(cas(v,WRITER)) {  // we are the writer
>             return
>         } else {
>             // loop and try again
>         }
>     }
> }
>
> wunlock() {
>     set(v,0);
>     cond.signal() // for other waiting writers
> }
>
> Obviously if you need readers to block on writers (i.e. rlock() ) it is 
> slightly more work, but you get the idea.
>
>
> On Dec 3, 2019, at 7:54 PM, Liam <networ...@gmail.com <javascript:>> 
> wrote:
>
> Busy means would-block, yes.
>
> Burak thanks, but that doesn't work for read-lock.
>
> On Tuesday, December 3, 2019 at 5:39:48 PM UTC-8, Robert Engels wrote:
>>
>> It depends then, because technically the Go RW lock queues readers behind 
>> a waiting writer so “busy” is somewhat undefined. If “busy” means “would 
>> block” you can still do it - I’ll post the code tonight. 
>>
>> > On Dec 3, 2019, at 6:49 PM, Robert Engels <ren...@ix.netcom.com> 
>> wrote: 
>> > 
>> > I would use an atomic and a lock instead of two locks. 
>> > 
>> >>> On Dec 3, 2019, at 6:35 PM, burak serdar <bse...@computer.org> 
>> wrote: 
>> >>> 
>> >>> On Tue, Dec 3, 2019 at 5:21 PM Liam Breck <networ...@gmail.com> 
>> wrote: 
>> >>> 
>> >>> I have a problem that is trivially solved via 
>> >>> 
>> >>> door sync.RWMutex 
>> >>> 
>> >>> func Reader() T { 
>> >>>  if !door.TryRLock() { // missing in stdlib :-( 
>> >>>     return busy 
>> >>>  } 
>> >>>  defer door.RUnlock() 
>> >>>  ... 
>> >>> } 
>> >>> 
>> >>> func Writer() { 
>> >>>  door.Lock() 
>> >>>  defer door.Unlock() 
>> >>>  ... 
>> >>> } 
>> >>> 
>> >>> How does one achieve this in Go? 
>> >> 
>> >> Two locks and a bool? 
>> >> 
>> >> var door=sync.Mutex{} 
>> >> var x=sync.Mutex{} 
>> >> var b bool 
>> >> 
>> >> func trylock() bool { 
>> >> x.Lock() 
>> >> if b { 
>> >> x.Unlock() 
>> >> return false 
>> >> } 
>> >> b=true 
>> >> door.Lock() 
>> >> x.Unlock() 
>> >> return true 
>> >> } 
>> >> 
>> >> unlock: 
>> >> 
>> >> x.Lock() 
>> >> b=false 
>> >> door.Unlock() 
>> >> x.Unlock() 
>> >> 
>> >> 
>> >> 
>> >> 
>> >>> 
>> >>> -- 
>> >>> You received this message because you are subscribed to the Google 
>> Groups "golang-nuts" group. 
>> >>> To unsubscribe from this group and stop receiving emails from it, 
>> send an email to golan...@googlegroups.com. 
>> >>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/CAKvHMgTO%3DxfFQ_u7aO9UE-1vHHEKmdhr47sro2mnp6DkEb6mPA%40mail.gmail.com.
>>  
>>
>> >> 
>> >> -- 
>> >> You received this message because you are subscribed to the Google 
>> Groups "golang-nuts" group. 
>> >> To unsubscribe from this group and stop receiving emails from it, send 
>> an email to golan...@googlegroups.com. 
>> >> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/golang-nuts/CAMV2RqrDeBNhkeswg%2BhdCf1kSzMEJduota%3D6UrNq4z2PQRtzEQ%40mail.gmail.com.
>>  
>>
>>
>>
> -- 
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to golan...@googlegroups.com <javascript:>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/golang-nuts/022a5bb5-be27-4721-afe4-7e08f4531a3d%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/golang-nuts/022a5bb5-be27-4721-afe4-7e08f4531a3d%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/24f60a17-c572-433f-b1ff-10cdad98458f%40googlegroups.com.

Reply via email to