为什么睡眠会禁用go中的互斥?
这是一个买票程序,当票子为0时,它将显示“卖完”。我想知道为什么我不能在buyTicket功能中添加睡眠,为什么ticket会是负数为什么睡眠会禁用go中的互斥?,go,mutex,sleep,Go,Mutex,Sleep,这是一个买票程序,当票子为0时,它将显示“卖完”。我想知道为什么我不能在buyTicket功能中添加睡眠,为什么ticket会是负数 func(t *Ticket) buyTicket() { if t.getSpareTicket() <= 0 { log.Print("sell out") return } t.mu.Lock() t.numTicket
func(t *Ticket) buyTicket() {
if t.getSpareTicket() <= 0 {
log.Print("sell out")
return
}
t.mu.Lock()
t.numTicket--
time.Sleep(time.Microsecond)
log.Printf("there are %d", t.numTicket)
t.mu.Unlock()
}
func (t *Ticket) getSpareTicket() int{
t.mu.Lock()
defer t.mu.Unlock()
return t.numTicket
}
func main() {
buyer := &Ticket{}
buyer.mu = sync.Mutex{}
buyer.numTicket = 100
for buyer.getSpareTicket() > 0 {
//time.Sleep(time.Microsecond)
go func() {
log.Printf("number buy a ticket")
buyer.buyTicket()
}()
}
time.Sleep(time.Second * 2)
//l := buyer.getSpareTicket()
//fmt.Println(l)
}
该计划存在几个问题: 1-for循环创建goroutines,而备用票证的数量不为零。这将创建许多goroutine,因为它们不会立即执行并减少票证数量 2-在买票,你检查,然后购买。另一个goroutine在一个goroutine检查后也可以进去做同样的事情,决定继续并买票
解决方案是修复buyTicket,使其在进入时锁定,在退出时解锁,并在不调用getSpareTicket的情况下检查票证计数,因为getSpareTicket也会锁定相同的互斥锁,这将导致死锁。发生这种情况是因为在goroutines开始运行之前已检查for条件。谢谢您的回答。当我在buyTicket中删除sleep时没有问题,我想知道为什么添加sleep可能会导致ticket变为负值。另外,我尝试了您的解决方案,它会死锁。如果您在输入buyTicket时锁定一次,返回时解锁,并且不在buyTicket中调用getSpareTicket,则不会死锁。使用睡眠时,互斥锁保持锁定的时间更长,这使得更有可能有多个GoRoutine调用getSpareTicket(),看到结果大于零,继续买票。然后,他们都等待进入关键区域,导致票数为负数。你的程序有一个没有睡眠的比赛。如果您运行它足够多次,它最终将失败。
2020/11/15 15:36:00 there are 2
2020/11/15 15:36:00 there are 1
2020/11/15 15:36:00 there are 0
2020/11/15 15:36:00 there are -1
2020/11/15 15:36:00 there are -2
2020/11/15 15:36:00 there are -3
2020/11/15 15:36:00 there are -4
2020/11/15 15:36:00 there are -5