You probably want to make the element type of the slice an atomic.Value,
instead of an interface{}. You shouldn't need a mutex then.

On Fri, Mar 11, 2022 at 7:31 AM Cameron Elliott <gara...@gmail.com> wrote:

>
>
> Ian, thank you very much for the suggestion to use atomics.
> Unfortunately, for a standard SPSC ring buffer, I don't think it does the
> trick.
>
>
> I am attaching a simple ring buffer program at the end.
>
> If you run 'go run -race main.go' on the example,
> a race will occur.
> The race that occurs is a write, then read to the
> same element of a slice on two different goroutines.
>
> Of course a race-detected is expected.
>
> This can be fixed by mutexing Put() and Get(),
> because through some magic, mutexs affect the tables/tags
> the race detector maintains in order to catch races.
>
> Using sync.atomic on the ring buffer indexes doesn't
> affect the race-detector state for read and writes.
>
> I spent more time investigating, it seems there are
> two ways to make a traditional ring buffer compatible
> with the race detector:
>
> 1. Use build tags to conditionally Lock/Unlock mutexes
> where you would not actually need them, in order to reset
> the race detector on the object crossing goroutines.
>
> 2. Use the pragma //go:linkname to get access to the 'runtime.race'
> functions, in order to call Enable()/Disable/ReleaseMerge/Aquire
> as sync.Pool does in order to make the race detector happy.
>
> If there are other methods, please let me know!
> Thanks for any feedback!
>
> Cameron/Seattle
>
>
>
>
>
>
>
> package main
>
> import (
>         "sync/atomic"
>         "time"
> )
>
> type RB struct {
>     //mu sync.Mutex
>         buf        []interface{}
>         start, end int64
> }
>
>
> const N = 10
>
> func NewRB() *RB {
>         return &RB{buf: make([]interface{}, N)}
> }
>
> func (r *RB) Put(x interface{}) {
> //    mu.Lock()
> //    defer mu.Unlock()
>
>         r.buf[r.end] = x
>         atomic.AddInt64(&r.end,1)
>         //r.end++
>         r.end %= N
>
> }
>
> func (r *RB) Get() interface{} {
> //    mu.Lock()
> //    defer mu.Unlock()
>
>         v := r.buf[r.start]
>         atomic.AddInt64(&r.start,1)
>         //r.start++
>         r.start %= N
>
>         return v
> }
>
> func main() {
>
>         r := NewRB()
>
>         go func() {
>                 r.Put(12345)
>         }()
>
>         time.Sleep(time.Millisecond)
>
>         a := r.Get().(int)
>         println(a)
> }
>
>
> --
> 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/d7cc3410-c0bb-40d6-bf75-5e655ba3136en%40googlegroups.com
> <https://groups.google.com/d/msgid/golang-nuts/d7cc3410-c0bb-40d6-bf75-5e655ba3136en%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/CAEkBMfGDrre6Rc4E-npy33-W8CZy7_ZT-w%3DCc4LskR7N015j6Q%40mail.gmail.com.

Reply via email to