一分耕耘,一分收获!既然打开了这篇文章《为什么 sleep 会禁用 go 中的互斥体?》,就坚持看下去吧!文中内容包含等等知识点...希望你能在阅读本文后,能真真实实学到知识或者帮你解决心中的疑惑,也欢迎大佬或者新人朋友们多留言评论,多给建议!谢谢!
问题内容这是一个buyticket程序,当ticket为0时,会显示“sell out”。我想知道为什么我不能在 buyticket 函数中添加 sleep 以及为什么 ticket 会是负数?
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)
}
当我在 buyticket 函数中添加 time.sleep(time.microsecond) 时,票证将为负数,我想知道为什么会发生这种情况?
这是结果:
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
解决方案
该程序存在几个问题:
1- for 循环创建 goroutine,而备用票数不为零。这将创建许多 goroutine,因为它们不会立即执行并减少票数
2- 在 buyTicket 中,您检查,然后购买。在一个 Goroutine 检查后,另一个 Goroutine 可以进去做同样的事情,决定继续并买一张票。
解决方案是修复 buyTicket 以在退出时锁定入口解锁,并在不调用 getSpareTicket 的情况下检查票证计数,因为 getSpareTicket 也会锁定相同的互斥锁,这将导致死锁。
本篇关于《为什么 sleep 会禁用 go 中的互斥体?》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注编程网公众号!