英文:
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()
	}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论