设置和从并发的goroutine中访问指针

huangapple go评论84阅读模式
英文:

Settings and accessing a pointer from concurrent goroutines

问题

在这段伪代码中,存在并发性的问题。具体来说,问题出现在goroutine A和goroutine B同时访问和修改map变量"a"的时候。

在goroutine A中,通过将map赋值给临时变量tempA来使用它。然而,在goroutine B中,通过将新创建的map赋值给变量a来替换原有的map。这样做可能会导致goroutine A在使用tempA期间,map被替换,从而导致数据不一致或错误的结果。

为了解决这个问题,你可以使用互斥锁(mutex)来保护map的访问和修改。在goroutine A中,在访问和使用map之前,获取互斥锁;在goroutine B中,在替换map之前,获取互斥锁。这样可以确保在一个goroutine修改map时,其他goroutine无法同时访问它,从而避免并发冲突。

另外,还可以考虑使用Go语言中提供的并发安全的数据结构,如sync.Map,它已经内置了并发访问的保护机制,可以更方便地处理并发访问map的情况。

英文:

I have a map which is used by goroutine A and replaced once in a time in goroutine B. By replacement I mean:

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 
    }
}

Do you see any problem in this pseudo code? (in terms of concurrecy)

答案1

得分: 7

代码不安全,因为对指针值的赋值和读取不能保证是原子操作。这意味着当一个goroutine写入新的指针值时,另一个goroutine可能会看到旧值和新值的混合字节,这将导致程序以不好的方式崩溃。另一件可能发生的事情是,由于代码中没有同步,编译器可能会注意到没有任何东西可以改变goroutineA中的a,并将tempA := a语句提升到循环之外。这意味着你将永远看不到其他goroutine更新的新映射赋值。

你可以使用go test -race自动查找这些问题。

一种解决方案是使用互斥锁锁定对映射的所有访问。

你可以阅读Go内存模型文档,该文档清楚地解释了何时在goroutine内部可见变量的更改。

英文:

The code isn't safe, since assignments and reads to a pointer value are not guaranteed to be atomic. This can mean that as one goroutine writes the new pointer value, the other may see a mix of bytes from the old and new value, which will cause your program to die in a nasty way. Another thing that may happen is that since there's no synchronisation in your code, the compiler may notice that nothing can change a in goroutineA, and lift the tempA := a statement out of the loop. This will mean that you'll never see new map assignments as the other goroutine updates them.

You can use go test -race to find these sorts of problems automatically.

One solution is to lock all access to the map with a mutex.

You may wish to read the Go Memory Model document, which explains clearly when changes to variables are visible inside goroutines.

答案2

得分: 3

当对数据竞争不确定时,运行go run -race file.go,也就是说,是的,会发生竞争。

最简单的解决方法是使用sync.RWMutex

var a map[T]N
var lk sync.RWMutex
// 使用该map
func goroutineA() {
    for (...) {
        lk.RLock()
        // 对a进行操作
        lk.RUnlock()
    }
}

// 刷新该map
func goroutineB() {
    for (...) {
        otherTempA = make(map[T]N)
        //...初始化其他的tempA....
        lk.Lock()
        a = otherTempA
        lk.Unlock()
    }
}
英文:

When unsure about data races, run go run -race file.go, that being said, yes there will be a race.

The easiest way to fix that is using a sync.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()
	}
}

huangapple
  • 本文由 发表于 2014年5月29日 13:54:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/23926601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定