Channels can be used to synchronize goroutines. A channel can make a goroutine wait until its finished. The channel can then be used to notify a 2nd goroutine.

Imagine you have several goroutines. Sometimes a goroutine needs to be finished before you can start the next one (synchronous). This can be solved with channels.

Channel synchronization

Example

Define a function to be used in the program. It can be a simple function like the one below:


func task(done chan bool) {
    fmt.Print("running...")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

This will output “running…”, wait, then print done and send “true” in the channel named ‘done’. The channel named ‘done’ is of type boolean (true or false).

The code would be this:


package main

import "fmt"
import "time"

func task(done chan bool) {
    fmt.Print("running...")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

func main() {
   done := make(chan bool,1)
   go task(done)

   <- done
}
    go run example.go
    running...done

Synchronizing goroutines

You can then make one goroutine wait for another goroutine. You can do that with an if statement and reading the channel value.


package main

import "fmt"
import "time"

func task(done chan bool) {
    fmt.Print("Task 1 (goroutine) running...")
    time.Sleep(time.Second)
    fmt.Println("done")

    done <- true
}

func task2() {
    fmt.Println("Task 2 (goroutine)")
}

func main() {
   done := make(chan bool,1)
   go task(done)


   if <- done {
       go task2()
       fmt.Scanln()
   }
}

Now goroutine task2 will wait for goroutine task to be finished.

Note

Thus these goroutines (task, task2) can be synchronous all the while running concurrently.

Because everything is concurrent, you can still use the main thread for your program, at the same time.


func main() {
   done := make(chan bool,1)
   go task(done)
 
   fmt.Println("Im in the main thread!")
   
   if <- done {
       go task2()
       fmt.Scanln()
    }
}