致命错误:goroutines睡着了 - 死锁

时间:2016-02-11 22:56:27

标签: go

尝试学习并发。我遇到了一个错误的问题:

fatal error: all goroutines are asleep - deadlock!

我被告知要添加一个等待组和一个关闭通道来修复该问题。我已经添加了这两个,但错误仍然存​​在。我不知道自己错了什么。

这是我的代码https://play.golang.org/p/ZB45oXlBUl

package main

import (
    "log"
    "sync"
    "time"
)

type RowInfo struct {
    id int64
}

func main() {
    queueChan := make(chan RowInfo)
    workerChan := make(chan RowInfo)
    doneChan := make(chan int64)
    closeChan := make(chan struct{})

    var waitGroup sync.WaitGroup

    go dispatcher(queueChan, workerChan, doneChan, closeChan)

    // Start WorkerCount number of workers
    workerCount := 4
    for i := 0; i < workerCount; i++ {
        go worker(workerChan, doneChan, &waitGroup)
    }

    // Send test data
    waitGroup.Add(12)
    for i := 0; i < 12; i++ {
        queueChan <- RowInfo{id: int64(i)}
    }

    // Prevent app close till finished execution
    waitGroup.Wait()

    close(closeChan)
}

func dispatcher(queueChan, workerChan chan RowInfo, doneChan chan int64, closeChan chan struct{}) {
    state := make(map[int64]bool)

    for {
        select {
        case job := <-queueChan:
            if state[job.id] == true {
                continue
            }
            workerChan <- job
        case result := <-doneChan:
            state[result] = false
        case <-closeChan:
            close(queueChan)
            close(workerChan)
            close(doneChan)
            break
        }
    }
}

func worker(workerChan chan RowInfo, doneChan chan int64, waitGroup *sync.WaitGroup) {
    for job := range workerChan {
        time.Sleep(1 * time.Second)
        log.Printf("Doing work on job rowInfo ID: %d", job.id)

        // Finish job
        doneChan <- job.id
        waitGroup.Done()
    }
}

错误:

2009/11/10 23:00:01 Doing work on job rowInfo ID: 2
2009/11/10 23:00:01 Doing work on job rowInfo ID: 0
2009/11/10 23:00:01 Doing work on job rowInfo ID: 3
2009/11/10 23:00:01 Doing work on job rowInfo ID: 1
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /tmp/sandbox490337982/main.go:32 +0x1e0

goroutine 5 [chan send]:
main.dispatcher(0x104360c0, 0x10436100, 0x10436140, 0x10436180)
    /tmp/sandbox490337982/main.go:50 +0x200
created by main.main
    /tmp/sandbox490337982/main.go:21 +0x100

goroutine 6 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
    /tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
    /tmp/sandbox490337982/main.go:26 +0x160

goroutine 7 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
    /tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
    /tmp/sandbox490337982/main.go:26 +0x160

goroutine 8 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
    /tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
    /tmp/sandbox490337982/main.go:26 +0x160

goroutine 9 [chan send]:
main.worker(0x10436100, 0x10436140, 0x104382e0, 0x0)
    /tmp/sandbox490337982/main.go:68 +0x1a0
created by main.main
    /tmp/sandbox490337982/main.go:26 +0x160

1 个答案:

答案 0 :(得分:1)

要了解此问题,请考虑dispatcherworkers发生了什么。

  1. 初始状态:调度员和工人闲置
  2. 发送队列Chan:调度员选择发送到workerChan
  3. workerChan by worker:睡4秒,写入doneChan。
  4. 2,3重复4次,直到所有工人都在睡觉
  5. 当所有工作人员都在睡觉时,另一份工作是在队列中进行的。
  6. 调度员去做那项工作
  7. 调度员无法发送workerChan,因为没有工人正在阅读。
  8. 所有工人都通过睡眠尝试发送doneChan。
  9. 现在所有的goroutine都被封锁了。