By Noettore


2015-04-06 20:56:46 8 Comments

I'm a GO newbie and I'm trying to figure out how does goroutines work and how to synchronize them. This is a simple program I wrote to learn something about them:

package main

import (
        "fmt"
        "sync"
        "time"
)

func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
        time.Sleep(delay)
        fmt.Println(message)
        wg.Done()
}

func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
        c := a + b
        chan1 <- c
        //close(chan1)
        wg.Done()
}

func printer(chan1 chan int, wg *sync.WaitGroup) {
        for result := range chan1 {
                //result := <-chan1
                //time.Sleep(2000 * time.Millisecond)
                fmt.Println(result)
        }
        close(chan1)
        wg.Done()
}

func main() {
        //var wg sync.WaitGroup
        wg := &sync.WaitGroup{}

        fmt.Println("Start...")

        wg.Add(1)
        go printAfterDelay(2000*time.Millisecond, "Try", wg)

        chan1 := make(chan int)
        wg.Add(1)
        go add(5, 4, chan1, wg)

        wg.Add(1)
        go add(3, 1, chan1, wg)

        wg.Add(1)
        go printer(chan1, wg)

        //time.Sleep(3000 * time.Millisecond)
        wg.Wait()

        fmt.Println("End")
}

The add function takes two int, sums them and pass the result to a chan. The printer function takes the results from the chan and print them. The two funtions are called in main() as goroutines, so i also passed a WaitGroup as a pointer, that is incremented before calling the goroutines and decremented when the functions end.

Anyway when I execute the compiled program it prints:

Start...
9
4
Try
fatal error: all goroutines are asleep - deadlock!
goroutine 16 [semacquire]:
sync.runtime_Semacquire(0x18334008)
  /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
sync.(*WaitGroup).Wait(0x183240e0)
  /usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
main.main()        
  /home/ettore/go/src/example/goroutine/main.go:52 +0x1e5

goroutine 19 [finalizer wait]:
runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
  /usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
runtime.parkunlock(0x814f000, 0x814e3e9)       
  /usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
frunfinq()        
  /usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
runtime.goexit()        
  /usr/lib/go/src/pkg/runtime/proc.c:1445

goroutine 23 [chan receive]:
main.printer(0x1831a090, 0x183240e0)        
  /home/ettore/go/src/example/goroutine/main.go:23 +0x46
created by main.main        
  /home/ettore/go/src/example/goroutine/main.go:49 +0x1d7

Where and what is the problem(s)?

Thanks!

1 comments

@Jerry Saravia 2015-04-07 02:30:16

The following works. By that I mean that it doesn't deadlock. Since you have the printer function in a range loop over the channel, it'll automatically stop after the channel is closed. I added the 3 sec delay near the end to give the try loop time to print. Read the documentation though. It'll explain 100% of these details.

package main

import (
        "fmt"
        "sync"
        "time"
)

func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
        time.Sleep(delay)
        fmt.Println(message)

}

func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
        c := a + b
        chan1 <- c
        wg.Done()
}

func printer(chan1 chan int, wg *sync.WaitGroup) {
        for result := range chan1 {
                fmt.Println(result)
        }
}

func main() {
        //var wg sync.WaitGroup
        wg := &sync.WaitGroup{}

        fmt.Println("Start...")

        go printAfterDelay(2000*time.Millisecond, "Try", wg)

        chan1 := make(chan int)
        wg.Add(1)
        go add(5, 4, chan1, wg)

        wg.Add(1)
        go add(3, 1, chan1, wg)

        go printer(chan1, wg)

        time.Sleep(3000 * time.Millisecond)
        wg.Wait()
    close(chan1)

        fmt.Println("End")
}

@Jerry Saravia 2015-04-07 02:43:55

By the way, you could remove the waitgroup altogether since the printer function will "freeze" and wait until either there is some value in the channel to read or it is closed.

@Noettore 2015-04-07 08:34:14

Thank you! I promise I'll read the whole documentation...

@JimB 2015-04-07 10:45:49

No, you do need the waitgroup (or equivalent). Otherwise there's no guarantee that the sending functions will compete before you close the channel and you will get a panic. Never use a sleep for synchronization.

Related Questions

Sponsored Content

7 Answered Questions

[SOLVED] How to correctly use sync.Cond?

3 Answered Questions

[SOLVED] Correct on input but panic on output in golang

  • 2016-12-27 14:57:07
  • aurelien
  • 257 View
  • 0 Score
  • 3 Answer
  • Tags:   go panic

2 Answered Questions

[SOLVED] How to connect remote ssh server with socks proxy?

  • 2016-03-19 12:58:58
  • Андрей Антонов
  • 969 View
  • 3 Score
  • 2 Answer
  • Tags:   go ssh proxy

1 Answered Questions

[SOLVED] Golang Goroutine Error "all goroutines are asleep - deadlock!"

1 Answered Questions

1 Answered Questions

2 Answered Questions

3 Answered Questions

[SOLVED] How to start a process?

  • 2012-12-17 11:40:17
  • dajood
  • 6982 View
  • 10 Score
  • 3 Answer
  • Tags:   go

1 Answered Questions

[SOLVED] GOLANG: fatal error: all goroutines are asleep - deadlock

  • 2015-02-03 13:51:35
  • Sidharth C. Nadhan
  • 1445 View
  • 1 Score
  • 1 Answer
  • Tags:   go deadlock goroutine

2 Answered Questions

[SOLVED] Why slice length greater than capacity gives runtime error?

  • 2011-08-16 19:07:21
  • Anuj Verma
  • 4387 View
  • 3 Score
  • 2 Answer
  • Tags:   go

Sponsored Content