go - 为什么互斥锁最终会出现线程正在休眠的错误?
问题描述
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 例程。预期的结果应该是旅客列车到达(等待 3 秒)-> 邮件列车想要到达(被要求等待)-> 旅客列车离开 - > 邮件列车收到通知,它到达并等待(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
解决方案
您收到此错误是因为func (pm *PlatformManager) notifyFree()
创建了一个 lock onpm.signal
然后调用nextTrain.PermitArrival()
它又试图获得一个 lock on pm.signal
。由于这种代码布局,nextTrain.PermitArrival()
永远不会被锁定pm.signal
,因此第 97 行出现错误。
您可以使用 goroutine 更优雅地实现这一点。您可以参考这个 ping pong示例开始。
推荐阅读
- python - Python 代码适用于解释器,但在我使用 pyinstaller 时不起作用
- c# - 如何在 Azure 应用服务中升级 .Net 框架之前或之后维护应用程序
- python - 如何绘制跨基因组坐标的 log2 倍数变化(使用 Deseq2 输出 csv)
- revit-api - 无法在 Revit 文件的视图中隐藏元素类别
- math - 圆形的二维标识符?
- javascript - JavaScript 从数组或函数为 nivo 生成 json 数据
- aws-api-gateway - serverless.yml 如何使用多个路径参数?
- sharedpreferences - 为什么 androidx PreferenceDataStore 不工作?
- javascript - 与模运算符混淆
- javascript - 检查元素是否:悬停(javascript或jquery)