随着程序中通道的引入,Go 程序陷入了解锁

问题描述 投票:0回答:1

我是 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 channel
1个回答
0
投票

我认为问题是你的 go 运行时无法检测到 sleep 函数。你故意设置了睡眠,这是有道理的,但 go 运行时不知道。所以

AllocMem
可能在 main 退出之前还没有完成分配。因此,这种模式是在您请求之前 Channel 没有填充数据,因此它是阻塞状态或死锁。

现在要解决这个问题,您可以引入一些 go 运行时可以理解的构造,并意识到您希望等到所有分配都在 main 退出之前完成。因此,只需在

sync.WaitGroup
之前创建
k.AllocMem()
并在使用
defer wg.Done()
调用之前添加 1 即可。只需添加
wg.Wait()
即可代替睡眠。这可能有用。

© www.soinside.com 2019 - 2024. All rights reserved.