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.

Reply via email to