面试题答案
一键面试检测竞争条件
在Go中,可以使用-race
标志来检测竞争条件。-race
标志会启用Go的竞态检测器,它会记录所有的内存访问操作,并在运行时检查是否存在数据竞争。
编写测试代码
假设我们有如下简单的银行账户转账代码:
package main
import (
"fmt"
)
var balance int
func transfer(from, to *int, amount int) {
*from = *from - amount
*to = *to + amount
}
func main() {
account1 := 100
account2 := 200
go transfer(&account1, &account2, 50)
go transfer(&account2, &account1, 30)
fmt.Println("Account 1:", account1)
fmt.Println("Account 2:", account2)
}
要测试这个代码是否存在竞争条件,可以将上述代码保存为main.go
,然后使用以下命令运行:
go run -race main.go
如果存在竞争条件,竞态检测器会输出相关信息,指出竞争发生的位置。
修改代码避免竞争
为了避免竞争条件,可以使用sync.Mutex
来保护共享资源。修改后的代码如下:
package main
import (
"fmt"
"sync"
)
var (
balance int
mu sync.Mutex
)
func transfer(from, to *int, amount int, wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
*from = *from - amount
*to = *to + amount
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
account1 := 100
account2 := 200
wg.Add(2)
go transfer(&account1, &account2, 50, &wg)
go transfer(&account2, &account1, 30, &wg)
wg.Wait()
fmt.Println("Account 1:", account1)
fmt.Println("Account 2:", account2)
}
在上述代码中,通过sync.Mutex
的Lock
和Unlock
方法来确保在同一时间只有一个goroutine可以访问共享资源(即账户余额),从而避免了竞争条件。