【发布时间】:2013-10-31 07:32:08
【问题描述】:
我正在尝试理解 Golang typical data races 之一,其中从多个 goroutine 访问未受保护的全局变量可能会导致竞争条件:
var service map[string]net.Addr
func RegisterService(name string, addr net.Addr) {
service[name] = addr
}
func LookupService(name string) net.Addr {
return service[name]
}
接着说我们可以通过使用互斥锁来保护它来解决这个问题:
var (
service map[string]net.Addr
serviceMu sync.Mutex
)
func RegisterService(name string, addr net.Addr) {
serviceMu.Lock()
defer serviceMu.Unlock()
service[name] = addr
}
func LookupService(name string) net.Addr {
serviceMu.Lock()
defer serviceMu.Unlock()
return service[name]
}
到目前为止,一切都很好。让我困惑的是:
this question 的公认答案表明,受 CPU 限制的 goroutine 将使任何已被多路复用到同一 OS 线程上的其他 goroutine 饿死(除非我们明确地使用 runtime.Gosched() 让步)。这是有道理的。
对我来说,上面的 RegisterService() 和 LookupService() 函数看起来受 CPU 限制,因为没有 IO 也没有产量。这是正确的吗?
如果是,并且如果 GOMAXPROCS 设置为 1,那么上面示例中的互斥锁仍然是绝对必要的吗? goroutine 在可能发生竞态条件的地方受 CPU 限制这一事实是否解决了这个问题?
即使是这样,我认为在现实生活中使用互斥锁仍然是一个好主意,因为我们可能无法保证 GOMAXPROCS 的设置。还有其他原因吗?
【问题讨论】:
-
Go 例程受 CPU 限制的事实并不意味着它们之间没有机会发生调度。互斥体仍然是必需的。
-
谢谢。因此,受 CPU 限制的 goroutine 可能会饿死同一 OS 线程上的其他 goroutine,也可能不会。无论哪种方式,我们都无法保证。如果是这样,你知道是什么因素决定了一个 goroutines 是否会饿死其他人吗?
-
一个 CPU Bound goroutine 用于在同一个线程上饿死其他人,但 Go 1.2(即将发布)有一个抢占式调度程序,因此不再是这种情况。恕我直言,这只是一个实现细节。 (在 go 1.2 中,每个函数调用都是抢占的机会,因此如果您的 CPU 绑定函数不调用其他函数,它将使同一线程上的其他函数挨饿)。
-
@AlexEdwards 如果您的代码对调度程序的行为做出任何假设,它就会利用未定义的行为。不要写这样的代码。假设调度程序可能会在代码中的每个点在 Goroutine 之间切换。
-
@NickCraig-Wood 你可能会发布它作为答案。
标签: go race-condition