【问题标题】:why sleep will disable the mutex in go?为什么 sleep 会禁用 go 中的互斥锁?
【发布时间】:2021-02-27 03:37:42
【问题描述】:

这是一个buyTicket程序,当ticket为0时,会显示“sell out”。我想知道为什么我不能在 buyTicket 函数中添加 sleep 以及为什么票会是负数?

 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)时,ticket会是负数,我想知道为什么会这样?

这是结果:

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

【问题讨论】:

  • 发生这种情况是因为在 goroutine 开始运行之前已经检查了 for 条件。

标签: go mutex sleep


【解决方案1】:

程序有几个问题:

1- for 循环创建 goroutines 备用票证的数量非零。这将创建许多 goroutine,因为它们不会立即执行并减少票数

2- 在 buyTicket 中,您检查,然后购买。在一个 goroutine 检查、决定继续并买票后,另一个 goroutine 可以进去做同样的事情。

解决的办法是修复buyTicket在退出时锁定进入解锁,并在不调用getSpareTicket的情况下检查票数,因为getSpareTicket也锁定了相同的互斥体,这会导致死锁。

【讨论】:

  • 感谢您的回答。我在buyTicket中删除sleep没有问题,我想知道为什么添加sleep会导致ticket变成负数。另外,我试过你的解决方案,它会死锁。
  • 进入buyTicket时加锁一次,返回解锁,buyTicket中不调用getSpareTicket,不会死锁。
  • 使用睡眠,互斥锁保持锁定的时间更长,使得更有可能有多个 goroutine 调用 getSpareTicket(),看到结果大于零并继续购买票。然后他们都等待进入临界区,导致负票数。你的程序有一场没有睡眠的比赛。如果你运行它足够多次,它最终会失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
相关资源
最近更新 更多