设置和访问并发程序中的指针



我有一个映射,由程序a使用,并在程序b中替换一次。这里的替换是指:

var a map[T]N
// uses the map
func goroutineA() {
    for (...) {
        tempA = a
        ..uses tempA in some way...
    }
}
//refreshes the map
func gorountineB() {
    for (...) {
        time.Sleep(10 * time.Seconds)
        otherTempA = make(map[T]N)
        ...initializes other tempA....
        a = otherTempA 
    }
}

你觉得这段伪代码有什么问题吗?(在并发性方面)

代码不安全,因为对指针值的赋值和读取不能保证是原子性的。这可能意味着,当一个程序写入新的指针值时,另一个程序可能会看到来自旧值和新值的混合字节,这将导致程序以一种糟糕的方式死亡。另一件可能发生的事情是,由于代码中没有同步,编译器可能会注意到没有任何东西可以改变gooutinea中的a,并将tempA := a语句从循环中取出。这意味着你永远不会看到新的映射赋值,因为其他例程更新了它们。

您可以使用go test -race自动查找这些类型的问题。

一个解决方案是用互斥锁锁定所有对map的访问。

你可能希望阅读Go内存模型文档,它清楚地解释了变量的更改何时在程序中可见。

当不确定数据竞赛时,运行go run -race file.go,也就是说,会有一场竞赛。

解决这个问题最简单的方法是使用同步。RWMutex:
var a map[T]N
var lk sync.RWMutex
// uses the map
func goroutineA() {
    for (...) {
        lk.RLock()
        //actions on a
        lk.RUnlock()
    }
}
//refreshes the map
func gorountineB() {
    for (...) {
        otherTempA = make(map[T]N)
        //...initializes other tempA....
        lk.Lock()
        a = otherTempA
        lk.Unlock()
    }
}

最新更新