atomic.AddInt64() 是否强制从/向主内存获取/更新值?

ove*_*nge -4 go goroutine

在下面的代码中使用atomic.AddInt64

func main() {

    // Number of goroutines to use.
    const grs = 2

    // wg is used to manage concurrency.
    var wg sync.WaitGroup
    wg.Add(grs)

    // Create two goroutines.
    for g := 0; g < grs; g++ {
        go func() {
            for i := 0; i < 2; i++ {
                atomic.AddInt64(&counter, 1)
            }

            wg.Done()
        }()
    }

    // Wait for the goroutines to finish.
    wg.Wait()

    // Display the final value.
    fmt.Println("Final Counter:", counter)
}
Run Code Online (Sandbox Code Playgroud)

或在下面的代码中使用atomic.LoadInt64

func writer(i int) {

    // Only allow one goroutine to read/write to the slice at a time.
    rwMutex.Lock()
    {
        // Capture the current read count.
        // Keep this safe though we can due without this call.
        rc := atomic.LoadInt64(&readCount)

        // Perform some work since we have a full lock.
        fmt.Printf("****> : Performing Write : RCount[%d]\n", rc)
        data = append(data, fmt.Sprintf("String: %d", i))
    }
    rwMutex.Unlock()
    // Release the lock.
}

// reader wakes up and iterates over the data slice.
func reader(id int) {

    // Any goroutine can read when no write operation is taking place.
    rwMutex.RLock()
    {
        // Increment the read count value by 1.
        rc := atomic.AddInt64(&readCount, 1)

        // Perform some read work and display values.
        time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
        fmt.Printf("%d : Performing Read : Length[%d] RCount[%d]\n", id, len(data), rc)

        // Decrement the read count value by 1.
        atomic.AddInt64(&readCount, -1)
    }
    rwMutex.RUnlock()
    // Release the read lock.
}
Run Code Online (Sandbox Code Playgroud)

是否atomic.AddInt64(&counter, 1)atomic.LoadInt64(&readCount)确保counter/ 的值readCount总是指主内存而不是 L1/L2 缓存?

kos*_*tix 5

恐怕你的想法有点错误。

原子内存操作不保证值将“刷新”到/从任何内存;它们仅保证多个并发运行的 CPU(内核)的内存视图的一致性。

也就是说,如果一个CPU执行atomic.AddInt64(&counter, 1),以及任何其他数量的CPU执行atomic.LoadInt64(&counter),它保证任何读取CPU的要么负荷值counter一号CPU之前增加它,或之后,而不是中途之间-比如,当整数的第一个 32 位部分已更新,但另一个尚未更新;任何原子负载都将保证看到增量或不看到增量,这取决于其关于更新的总排序。

此外,如果两个 CPU 碰巧atomic.AddInt64(&counter, 1)“同时”发出命令,则可以保证在这些操作中的最后一个完成时,counter至少增大2(前提是没有其他 CPU 同时原子地递减该计数器) )——也就是说,保证不会因某种冲突而丢失增量,并且如果需要,它们将按未指定的顺序正确地相互序列化。

重申一下,原子操作是关于一致性的;他们没有说明如何确保这种一致性(无论如何这将高度依赖于硬件)。