GoLang中使用渠道的优先队列

时间:2018-11-18 20:52:36

标签: go deadlock priority-queue channels

Question

上图中是我需要提供解决方案的问题。这是我想出的解决方案(必须在Go中编码)。我遇到了死锁错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /home/kypriank/Assignment 5/priorityqueue.go:42 +0x1a3

goroutine 17 [chan send]:
main.priorityQueue(0xc420080060, 0xc4200800c0)
    /home/kypriank/Assignment 5/priorityqueue.go:22 +0x1a2
created by main.main
    /home/kypriank/Assignment 5/priorityqueue.go:40 +0xe5
exit status 2

想知道是否有人可以帮助我弄清楚我的代码在哪里(主要功能有一些代码可以测试我的解决方案):

package main

var numOrder [20] int
var mesOrder [] PriorityMessage
var pri int
var a int

type PriorityMessage struct {
    Priority int // between 0 and 9
    Message string
}

func priorityQueue(west chan PriorityMessage, east chan string) {
    incomming := <-west
    if numOrder[incomming.Priority] == 10 {
        numOrder[incomming.Priority] = incomming.Priority
    }else {numOrder[incomming.Priority+1] = incomming.Priority}
    mesOrder = append(mesOrder, incomming)
    for i := 0; i < len(numOrder); i++ {if numOrder[i] != 10 {pri = 
numOrder[i]; a = i; break}}
    for i := 0; i < len(mesOrder); i++ {
        if pri == mesOrder[i].Priority {
            east <- (mesOrder[i]).Message
            numOrder[a] = 10
            mesOrder = append(mesOrder[:i], mesOrder[i+1:]...) 
        }
    }
}

var west chan PriorityMessage
var east chan string

func printToScreen() {
    for {println(<- east)}
}

func main() {
    for i := 0; i < len(numOrder); i++ {numOrder[i] = 10}
    west = make(chan PriorityMessage)
    east = make(chan string)
    go priorityQueue(west, east)
    west <- PriorityMessage{1, "one"}
    west <- PriorityMessage{0, "zero"}
    west <- PriorityMessage{2, "two"}
    west <- PriorityMessage{1, "another one"}
    west <- PriorityMessage{0, "another zero"}
    go printToScreen()
    select {} // to allow all messages to be printed
}

1 个答案:

答案 0 :(得分:0)

我并不是真正关注优先级队列的行为,而是专注于死锁。

因此,您有一些问题会给您带来僵局:

  1. 您仅从west中读取一次,但是您多次写入。这意味着它将在您写入zero时阻塞。也许添加一个for循环。
  2. go printToScreen()是对west的所有写操作。这意味着当您从west进行例行读取然后写入east的内容进入写作部分时,它将阻塞,因为没有任何内容从east进行读取。
  3. 空选择(select{})。尽管这将阻塞主执行例程,但它将无限期地执行。一旦其他所有go例程关闭,这将导致死锁恐慌。

我将您的代码更改为此:

package main

import "time"

var numOrder [20]int
var mesOrder []PriorityMessage
var pri int
var a int

type PriorityMessage struct {
    Priority int // between 0 and 9
    Message  string
}

func priorityQueue(west chan PriorityMessage, east chan string) {
    for {
        incomming := <-west
        if numOrder[incomming.Priority] == 10 {
            numOrder[incomming.Priority] = incomming.Priority
        } else {
            numOrder[incomming.Priority+1] = incomming.Priority
        }
        mesOrder = append(mesOrder, incomming)
        for i := 0; i < len(numOrder); i++ {
            if numOrder[i] != 10 {
                pri =
                    numOrder[i]
                a = i
                break
            }
        }
        for i := 0; i < len(mesOrder); i++ {
            if pri == mesOrder[i].Priority {
                east <- (mesOrder[i]).Message
                numOrder[a] = 10
                mesOrder = append(mesOrder[:i], mesOrder[i+1:]...)
            }
        }
    }
}

var west chan PriorityMessage
var east chan string

func printToScreen() {
    for {
        println(<-east)
    }
}

func main() {
    for i := 0; i < len(numOrder); i++ {
        numOrder[i] = 10
    }
    go printToScreen()
    west = make(chan PriorityMessage)
    east = make(chan string)
    go priorityQueue(west, east)
    west <- PriorityMessage{1, "one"}
    west <- PriorityMessage{0, "zero"}
    west <- PriorityMessage{2, "two"}
    west <- PriorityMessage{1, "another one"}
    west <- PriorityMessage{0, "another zero"}

    time.Sleep(time.Hour)
}

并执行以下结果:

one
zero
two
another one
another zero