为什么互斥锁最终会出现线程正在休眠的错误?

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    manager := NewPlatformManager()
    pTrain := &Passengertrain{mediator:manager}
    mTrain := &MailTrain{mediator:manager}
    pTrain.Arrive()
    mTrain.Arrive()
    pTrain.Depart()
    //pTrain.Arrive()
    //mTrain.Depart()
    //time.Sleep(20000 * time.Millisecond)
}

/*
Mediator pattern
*/
type Train interface {
    Arrive()
    Depart()
    PermitArrival()
}

type Mediator interface {
    allowLanding(Train) bool
    notifyFree()
}

type Passengertrain struct {
    mediator Mediator
}

func (t *Passengertrain) Arrive() {
    if !t.mediator.allowLanding(t) {
        fmt.Println("Station Busy,passenger train")
    } else {
        fmt.Println("Landing on station,passenger train")
        time.Sleep(3000 * time.Millisecond)
    }
}

func (t *Passengertrain) Depart() {
    t.mediator.notifyFree()
    fmt.Println("leaving station,passenger train")
}

func (t *Passengertrain) PermitArrival() {
    fmt.Println("Allowed to arrive,passenger train")
    t.Arrive()
}

type MailTrain struct {
    mediator Mediator
}

func (t *MailTrain) Arrive() {
    if !t.mediator.allowLanding(t) {
        fmt.Println("Station Busy,mail train")
    } else {
        fmt.Println("Landing on station,mail train")
        time.Sleep(5000 * time.Millisecond)
    }
}

func (t *MailTrain) Depart() {
    t.mediator.notifyFree()
    fmt.Println("leaving station,mail train")
}

func (t *MailTrain) PermitArrival() {
    fmt.Println("Allowed to arrive,mail train")
    t.Arrive()
}

type PlatformManager struct {
    queue     []Train
    signal    *sync.Mutex
    isBlocked bool
}

func NewPlatformManager() Mediator {
    instance := &PlatformManager{
        queue:     make([]Train,0),signal:    &sync.Mutex{},isBlocked: false,}
    return instance
}

func (pm *PlatformManager) allowLanding(train Train) bool {
    pm.signal.Lock()
    defer pm.signal.Unlock()
    if !pm.isBlocked {
        pm.isBlocked = true
        return true
    }
    pm.queue = append(pm.queue,train)
    return false
}

func (pm *PlatformManager) notifyFree() {
    pm.signal.Lock()
    defer pm.signal.Unlock()

    if pm.isBlocked {
        pm.isBlocked = false
    }
    if len(pm.queue) > 0 {
        nextTrain := pm.queue[0]
        pm.queue = pm.queue[1:]
        nextTrain.PermitArrival()
    }
}

我得到如下错误,我期望代码在单一流程中运行,也没有定义任何go例程。预期的结果应该是passengertrain到达(等待3秒)-> mailTrain要到达(被要求等待)-> passengertrain离开-> mailTrain被通知并到达并等待(5秒)

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_SemacquireMutex(0xc00002c00c,0x486700,0x1)
    /usr/local/go-faketime/src/runtime/sema.go:71 +0x47
sync.(*Mutex).lockSlow(0xc00002c008)
    /usr/local/go-faketime/src/sync/mutex.go:138 +0xfc
sync.(*Mutex).Lock(...)
    /usr/local/go-faketime/src/sync/mutex.go:81
main.(*PlatformManager).allowLanding(0xc000060150,0x4dd220,0xc000010210,0x0)
    /tmp/sandbox325139098/prog.go:97 +0x17d
main.(*MailTrain).Arrive(0xc000010210)
    /tmp/sandbox325139098/prog.go:63 +0x48
main.(*MailTrain).PermitArrival(0xc000010210)
    /tmp/sandbox325139098/prog.go:78 +0x83
main.(*PlatformManager).notifyFree(0xc000060150)
    /tmp/sandbox325139098/prog.go:117 +0xbb
main.(*Passengertrain).Depart(0xc000010200)
    /tmp/sandbox325139098/prog.go:49 +0x37
main.main()
    /tmp/sandbox325139098/prog.go:15 +0x13b

我在操场https://play.golang.org/p/JO2mEQSk_kI上跑了

iCMS 回答:为什么互斥锁最终会出现线程正在休眠的错误?

您收到此错误消息是因为func (pm *PlatformManager) notifyFree()pm.signal上创建了一个锁,然后调用nextTrain.PermitArrival(),这又试图在pm.signal上获得了锁。由于这种代码布局,nextTrain.PermitArrival()将永远无法锁定pm.signal,因此在第97行出现了错误。

您可以使用go例程更优雅地实现此功能。您可以先参考this ping pong示例。

本文链接:https://www.f2er.com/1983763.html

大家都在问