标签: synchronization

为什么竞态检测器在这里报告竞态条件?

我正在使用 Go 竞争检测(-race 参数),它检测到一些我认为不应该报告的竞争条件问题。我创建了这个示例代码来解释我的发现。请不要对此示例的目标发表评论,因为它除了解释问题之外没有其他目标。

这段代码:

var count int

func main() {
    go update()
    for {
        fmt.Println(count)
        time.Sleep(time.Second)
    }
}

func update() {
    for {
        time.Sleep(time.Second)
        count++
    }
}
Run Code Online (Sandbox Code Playgroud)

报告有竞争条件。

虽然这段代码:

var count int
var mutex sync.RWMutex

func main() {
    go update()
    for {
        mutex.RLock()
        fmt.Println(count)
        mutex.RUnlock()
        time.Sleep(time.Second)
    }
}

func update(){
    for {
        time.Sleep(time.Second)
        mutex.Lock()
        count++
        mutex.Unlock()
    }
}
Run Code Online (Sandbox Code Playgroud)

没有报告任何竞争条件问题。

我的问题是为什么?第一个代码中没有错误。main 函数正在读取另一个 go 例程正在更新的变量。这里没有潜在的隐藏错误。第二个代码互斥锁不提供任何不同的行为。

我哪里错了?

synchronization mutex global-variables go race-condition

-2
推荐指数
1
解决办法
104
查看次数

通过使用sync.Once实现“完美单例”?

我很困惑,下面的代码片段完美吗?

import "sync"
import "sync/atomic"

var initialized uint32
var instance *singleton

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}
Run Code Online (Sandbox Code Playgroud)

atomic.StoreUint32(&initialized, 1)会将实例刷新到所有CPU吗?我想我需要添加一个原子存储并加载,例如下面的代码片段

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        atomic.StorePointer(&instance, &singleton{})
    })
    return atomic.LoadPointer(&instance)
}
Run Code Online (Sandbox Code Playgroud)

我认为 Once.Do 只能保证函数 f 执行一次。并且atomic.StoreUint32(&o.done, 1)只是 o.done 的内存障碍。它不能确保instance全局可见

func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
    // Slow-path.
    o.m.Lock()
    defer …
Run Code Online (Sandbox Code Playgroud)

synchronization go

-3
推荐指数
1
解决办法
5008
查看次数

同步一次实现

我在Go 1.12中有一个关于sync.Once()的问题。源代码如下:

// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.

func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
    // Slow-path.
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么不只使用一个uint32变量,然后对该变量执行CAS。它似乎更有效,并且不会导致死锁。

代码如下:

type Once uint32
func (o *Once) Do(f func()) {
    if atomic.CompareAndSwapUint32((*uint32)(o), 0, 1) {
        f()
    }
}
Run Code Online (Sandbox Code Playgroud)

synchronization go

-5
推荐指数
1
解决办法
102
查看次数

-7
推荐指数
1
解决办法
730
查看次数