【问题标题】:Does the following lock-free code exhibit a race-condition?以下无锁代码是否表现出竞争条件?
【发布时间】:2016-12-23 01:34:44
【问题描述】:

Kubernetes Go repo on Github.com内,

HighWaterMark 数据结构有一个无锁实现。此代码依赖于原子操作来实现没有数据竞争的线程安全代码。

// HighWaterMark is a thread-safe object for tracking the maximum value seen
// for some quantity.
type HighWaterMark int64

// Update returns true if and only if 'current' is the highest value ever seen.
func (hwm *HighWaterMark) Update(current int64) bool {
    for {
        old := atomic.LoadInt64((*int64)(hwm))
        if current <= old {
            return false
        }
        if atomic.CompareAndSwapInt64((*int64)(hwm), old, current) {
            return true
        }
    }
}

此代码依赖于标准库中的 atomic.LoadInt64atomic.CompareAndSwapInt64 函数来实现无数据竞争的代码......我相信确实如此,但我相信还有另一个竞争条件问题。

如果两个竞争线程 (goroutines) 正在执行此类代码,则存在一种极端情况,即在第一个线程中出现 atomic.LoadInt64 之后,第二个线程可能已换出更高的值。但是在第一个线程认为之后,current int64 实际上大于old int64,就会发生交换。由于观察到陈旧的old 值,此交换将有效地降低存储值。

【问题讨论】:

    标签: multithreading go lock-free compare-and-swap


    【解决方案1】:

    如果另一个线程进入中间,CompareAndSwap 将失败,循环将重新开始。

    将 CompareAndSwap 视为

    if actual == expected { 
       actual = newval
    }
    

    但以原子方式完成

    所以这段代码说:

    old = hwm // but done in a thread safe atomic read way
    if old < current {
       set hwm to current if hwm == old // atomically compare and then set value
    }
    

    当 CAS (CompareAndSwap) 失败时,它返回 false,导致循环重新开始,直到:

    a) “当前”不大于 hwm

    b) 它成功地执行 Load 然后 CompareAndSwap 中间没有另一个线程

    【讨论】:

    • 啊哈!在阅读了您的答案大约 5 次后,它刚刚为我点击了。
    猜你喜欢
    • 1970-01-01
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-30
    • 1970-01-01
    • 2014-11-08
    • 1970-01-01
    相关资源
    最近更新 更多