我是 go 频道的新手, 我正在尝试通过构建模拟内核来学习 go 通道并通过通道处理通信。此示例程序的目的是让多个进程 (2) 使用单个通道向内核发送
memory
请求。然而,我的程序陷入了死锁。
package main
import (
"fmt"
"log"
"time"
)
const (
_ float64 = iota
LowPrio
MedPrio
HghPrio
)
// Kernel type to communicate between processes and memory resources
type Kernel struct {
reqMemCh chan chan int
}
func (k *Kernel) Init() {
k.reqMemCh = make(chan chan int, 2)
}
// Fetch memory on process request
func (k *Kernel) GetReqMemCh() chan chan int {
return k.reqMemCh
}
func (k *Kernel) AllocMem() {
// loop over the items (process reply channels) received over
// the request channel
for pCh := range k.GetReqMemCh() {
// rpCh := make(chan int)
// m := <-rpCh
// for now think 0 is the available index
// send this as a reply to the exclusive process reply channel
pCh <- 0
close(pCh)
}
}
// Process type which requests memory
type Proc struct {
ind int
prio float64
exeT time.Time
count int
memInd int
rqMemCh chan chan int
}
func (p *Proc) Init(
ind int,
prio float64,
rqMemCh chan chan int,
) {
p.ind = ind
p.prio = prio
p.memInd = -1
p.rqMemCh = rqMemCh
}
func (p *Proc) GetReqMemCh() chan chan int {
return p.rqMemCh
}
func (p *Proc) ReqMem() {
// create the reply channel exclusive to the process
// this channel will return the allocated memeory id/address
rpCh := make(chan int)
// send the reply channel through the request channel
// to get back the allocation memory id
p.GetReqMemCh() <- rpCh
// Below line is blocking ...
for mi := range rpCh {
p.memInd = mi
}
}
func (p Proc) String() string {
return fmt.Sprintf(
"Proc(%d): Memory(%d), Count(%d)",
p.ind+1, p.memInd+1, p.count,
)
}
func main() {
k := &Kernel{}
k.Init()
go k.AllocMem()
p := &Proc{}
for i := 0; i < 1; i++ {
p.Init(i, LowPrio, k.GetReqMemCh())
p.ReqMem()
}
time.Sleep(time.Second)
}
输出:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.(*Proc).ReqMem(...)
main.go:65
main.main()
main.go:86 +0x14e
goroutine 6 [chan receive]:
main.(*Kernel).AllocMem(0x0?)
main.go:31 +0x59
created by main.main in goroutine 1
main.go:81 +0x98
exit status 2
有人可以指出我做错了什么以及我怎样才能实现这样的设计
+--------+
| | +---------+
| P1 -\ | |
| |--\ +----------------------+ | |
+--------+ -\ | | | KERNEL |
--| CHANNEL -------| |
-/ | | | |
+---------+ -/ +----------------------+ | |
| -/ +---------+
| P2 /|
| |
+---------+
使用
go
频道。
干杯,
DD
我认为问题是你的 go 运行时无法检测到 sleep 函数。你故意设置了睡眠,这是有道理的,但 go 运行时不知道。所以
AllocMem
可能在 main 退出之前还没有完成分配。因此,这种模式是在您请求之前 Channel 没有填充数据,因此它是阻塞状态或死锁。
现在要解决这个问题,您可以引入一些 go 运行时可以理解的构造,并意识到您希望等到所有分配都在 main 退出之前完成。因此,只需在
sync.WaitGroup
之前创建 k.AllocMem()
并在使用 defer wg.Done()
调用之前添加 1 即可。只需添加 wg.Wait()
即可代替睡眠。这可能有用。