Marcos Oliveira
Marcos Oliveira

Reputation: 1697

all go routines are asleep - deadlock

I'm building the skeleton of a worker system using Go and I'm getting the "fatal error: all goroutines are asleep - deadlock!".

I am using two channels for coordination, one to create the jobs and the second to send the results. After creating the jobs I close the input channel.

My question is how I close the output channel so the program can exit correctly. The code is:

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "math/rand"
    "os"
    "time"
)

type Work struct {
    id int
    ts time.Duration
}

const (
    NumWorkers = 5000
    NumJobs    = 100000
)

func worker(in <-chan *Work, out chan<- *Work) {
    for w := range in {
        st := time.Now()
        time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
        w.ts = time.Since(st)
        out <- w
    }
}

func main() {
    wait := flag.Bool("w", false, "wait for <enter> before starting")
    flag.Parse()

    if *wait {
        fmt.Printf("I'm <%d>, press <enter> to continue", os.Getpid())
        reader := bufio.NewReader(os.Stdin)
        reader.ReadString('\n')
    }

    Run()
}

func Run() {
    in, out := make(chan *Work, 100), make(chan *Work, 100)
    for i := 0; i < NumWorkers; i++ {
        go worker(in, out)
    }
    go createJobs(in)
    receiveResults(out)
}

func createJobs(queue chan<- *Work) {
    for i := 0; i < NumJobs; i++ {
        work := &Work{i, 0}
        queue <- work
    }
    close(queue)
}

func receiveResults(completed <-chan *Work) {
    for w := range completed {
        log.Printf("job %d completed in %s", w.id, w.ts)
    }
}

Any help is appreciated :)

Upvotes: 1

Views: 454

Answers (1)

Arjan
Arjan

Reputation: 21465

I missed the part about you knowing the cause of deadlock in original answer.

  • You mentioned WaitGroup, that is basically just a semaphore
  • You could use another "control" channel that workers sinal on when they are done

-

func worker(ctrl chan<- bool, in <-chan *Work, out chan<- *Work) {
    for w := range in {
        st := time.Now()
        time.Sleep(time.Duration(rand.Int63n(int64(200 * time.Millisecond))))
        w.ts = time.Since(st)
        out <- w
    }
    ctrl <- true
}

func control(ctrl <-chan bool, numWorkers int, out chan<- *Work) {
    for i=0; i<numWorkers; i++ {
        <-ctrl
    }
    close(out)
}

original answer:

You do a range on completed:

for w := range completed {
    log.Printf("job %d completed in %s", w.id, w.ts)
}

but that channel is never closed

Upvotes: 1

Related Questions