【问题标题】:Priority queue in GoLang using channelsGoLang 中使用通道的优先级队列
【发布时间】:2019-04-21 06:20:32
【问题描述】:

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
}

【问题讨论】:

  • 优先队列是CS中的标准数据类型,不需要并发来实现-en.wikipedia.org/wiki/Priority_queue#Usual_implementation
  • 不幸的是,任务要求我使用并发来实现这一点。但是感谢您的输入 Dimitry :) 提供了大部分代码。我必须自己实现的唯一部分代码是 PriorityQueue 函数。

标签: go deadlock priority-queue channels


【解决方案1】:

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

所以你有几个问题会让你陷入僵局:

  1. 您只从west 读取一次,但是您正在多次写入。这意味着当你写zero时它会阻塞。也许添加一个for 循环。
  2. go printToScreen() 是对west 的所有写入。这意味着当你的 goroutine 从 west 读取然后写入 east 到达写入部分时,它将阻塞,因为没有从 east 读取。
  3. 空选 (select{})。虽然这会阻塞主 go 例程,但它会无限期地阻塞。一旦所有其他 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

【讨论】:

  • 非常感谢您的深入解释和您提供的解决方案 poy!正如我之前提到的,不幸的是,除了priorityQueue 函数中的代码之外,我不允许更改任何代码。我创建的变量是 numOrder、mesOrder、pri 和 a。所以除了这 4 个之外,priorityQueue 函数中的任何内容都不能更改。
  • 很公平,但这意味着你必须不断地从西方消费,而不是被东方阻挡。因此,在函数中插入 for 循环,然后在向东写入时,在新的 go 例程中执行此操作。
猜你喜欢
  • 2022-01-06
  • 2010-09-29
  • 2011-12-20
  • 1970-01-01
  • 2023-02-25
  • 1970-01-01
  • 2013-02-13
  • 1970-01-01
  • 2012-02-24
相关资源
最近更新 更多