Golang中这是否属于竞态条件?
Golang中这是否属于竞态条件? 大约一小时前,我被要求创建一个竞态条件并用互斥锁解决它。
我编写了以下代码来描绘一个竞态条件:
func main() {
var data int
go func() {
data++
}()
if data == 0 {
fmt.Println("The value of data is", data)
} else {
fmt.Println("The value of data is", data)
}
}
然后我添加了互斥锁来解决竞态条件,如下所示:
func main() {
var data int
var mu sync.Mutex
go func() {
mu.Lock()
data++
mu.Unlock()
}()
mu.Lock()
if data == 0 {
fmt.Println("The value of data is", data)
} else {
fmt.Println("The value of data is", data)
}
mu.Unlock()
}
面试官评论说第一段代码并没有描绘出竞态条件。如果我说错了请纠正我,但我认为它确实描绘了,你能帮忙解释一下吗?
更多关于Golang中这是否属于竞态条件?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
谢谢。出于某种原因,面试官认为这不是一个竞态条件。
这确实是一个数据竞争。你可以通过使用 -race 标志运行程序来确认这一点。
是的,确实如此。我想用一个更清晰的例子来演示这一点,这个例子包含多个非主函数的 goroutine。我也用 -race 参数运行了他的代码,并且检测到了数据竞争。
// 代码示例应放置于此
我认为Go将代码标记为存在竞态条件,是因为你从一个goroutine中访问了一个全局变量。当两个线程同时访问一个共享变量时,就会发生竞态条件。
如果你在运行程序时不使用竞态检测标志,程序会正常运行(因为goroutine没有机会被执行)。
实际上,这正是 @MukulLatiyan 的代码所做的事情。这里有两个执行线程(新启动的 goroutine 和主代码线程,在此上下文中主线程也可被视为一个 goroutine),并且其中一个执行了写操作。
package main
import (
"fmt"
"time"
)
func main() {
var data int
go func() {
data++
}()
time.Sleep(100 * time.Millisecond)
if data == 0 {
fmt.Printf("the value is %v.\n", data)
}
}
你遇到了一个竞态条件。数据竞争的发生需要满足两个或更多 goroutine 同时访问同一个变量,并且其中至少有一个访问是写操作,就像下面这样:
package main
var balance int
func Deposit(amount int) {
balance = balance + amount
}
func Balance() int {
return balance
}
func main() {
go Deposit(200)
go Deposit(100)
}
要解决这个问题:
package bank
import "sync"
var (
mu sync.Mutex
balance int
)
func Deposit(amount int) {
mu.Lock()
balance = balance + amount
mu.Unlock()
}
func Balance() int {
mu.Lock()
defer mu.Unlock()
return balance
}
你可以在以下仓库中找到更多示例:https://github.com/adonovan/gopl.io/tree/master/ch9 http://www.gopl.io/
是的,第一段代码确实存在竞态条件。竞态条件发生在多个goroutine并发访问共享变量且至少有一个是写入操作时,而代码的执行结果依赖于goroutine的执行顺序。
在你的例子中:
func main() {
var data int
go func() {
data++ // 写入操作
}()
if data == 0 { // 读取操作
fmt.Println("The value of data is", data)
} else {
fmt.Println("The value of data is", data)
}
}
存在三种可能的执行顺序:
- goroutine先执行:
data++先执行,输出显示The value of data is 1 - 读取先执行:
if data == 0先执行,输出显示The value of data is 0 - 读取发生在写入中间:
data++不是原子操作,可能读取到中间状态
使用互斥锁的解决方案是正确的:
func main() {
var data int
var mu sync.Mutex
go func() {
mu.Lock()
data++
mu.Unlock()
}()
mu.Lock()
if data == 0 {
fmt.Println("The value of data is", data)
} else {
fmt.Println("The value of data is", data)
}
mu.Unlock()
}
这个解决方案确保了data++和读取操作是互斥的,消除了竞态条件。输出结果现在是确定性的,不会依赖于goroutine的执行顺序。

