Thanks to Robert Clapis via Twitter
<https://twitter.com/rogpeppe/status/1202266693541748736> for this
suggestion, using channels. As he said, it doesn't quite get there, because
a reader can still acquire the lock even when a writer has requested it,
but it's still potentially useful and reasonably simple:

https://play.golang.org/p/N33t7uyxeiM

On Wed, 4 Dec 2019 at 18:34, Liam <networkimp...@gmail.com> wrote:

> 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> 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.
>> 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
> <https://groups.google.com/d/msgid/golang-nuts/24f60a17-c572-433f-b1ff-10cdad98458f%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/CAJhgacjdqHoyZeXfPFp%3DSET4MgobijntFFm0bg%3Dv3hok6ySzdA%40mail.gmail.com.

Reply via email to