Waiting for all goroutines to finish before ending main

7,157 views
Skip to first unread message

Roger Pau Monné

unread,
Mar 8, 2010, 7:40:03 AM3/8/10
to golang-nuts
Hello,

I'm used to program in C with the standard Unix libraries, is there anything like wait() in Go, so that I can wait for all goroutines to end before finishing main?

Thanks, Roger.

Ostsol

unread,
Mar 8, 2010, 7:51:27 AM3/8/10
to golang-nuts
The standard practice in Go seems to be for goroutines to pass to a
channel so signal their end. For example:

package main

func routine(quit chan int) {
// do stuff
quit <- 1
}

func main() {
routineQuit := make(chan int)
go routine(routineQuit)

<-routineQuit // blocks until quit is written to
}

-Daniel

Roger Pau Monné

unread,
Mar 8, 2010, 2:01:47 PM3/8/10
to Ostsol, golang-nuts
Since I launch many goroutines using a for loop, I use the following construction for waiting them to end:

for j :=  0; j < *concurrency; _, j = <- sem, j+1 { }

I just wanted to know if this was the best way for doing this, although I have to say that I'm missing the wait() system call.

2010/3/8 Ostsol <ost...@gmail.com>

Ian Lance Taylor

unread,
Mar 8, 2010, 2:40:32 PM3/8/10
to Roger Pau Monné, Ostsol, golang-nuts
Roger Pau Monné <roy...@gmail.com> writes:

> Since I launch many goroutines using a for loop, I use the following
> construction for waiting them to end:
>
> for j := 0; j < *concurrency; _, j = <- sem, j+1 { }
>
> I just wanted to know if this was the best way for doing this, although I
> have to say that I'm missing the wait() system call.

It depends on the rest of your program, of course, but looping until
you've read a value from each goroutine is perfectly reasonable. That
actual code won't work in Go because of the comma, and reading a value
from the channel and using that in the loop seems odd.

Ian

Roger Pau Monné

unread,
Mar 8, 2010, 2:50:13 PM3/8/10
to Ian Lance Taylor, Ostsol, golang-nuts
This code works, but yes, it might be more simple and easy to read to get the value of the channel inside of the loop.

2010/3/8 Ian Lance Taylor <ia...@google.com>

Michael Speer

unread,
Mar 8, 2010, 7:17:42 PM3/8/10
to Roger Pau Monné, Ian Lance Taylor, Ostsol, golang-nuts
Would something like this be helpful?

http://michaelspeer.blogspot.com/2010/03/go-language-is-lovely.html

//// "dispatch.go"

package dispatch

import "sync"

type Manager interface {
Go( func() )
Wait()
}

type manager struct {
lock sync.Mutex
running uint
waiting uint
wakeup chan bool
}

func New() *manager {
m := new(manager)
m.wakeup = make(chan bool)
return m
}

func (m *manager) Go( fn func() ) {
m.lock.Lock()
m.running++
m.lock.Unlock()

go func(){
fn()

m.lock.Lock()
m.running--
if (m.running == 0) && (m.waiting > 0) {
oc := m.wakeup
nc := make(chan bool)
i := m.waiting
go func(){
for ; i > 0 ; i-- {
oc <- true
}
}()
m.wakeup = nc
m.waiting = 0
}
m.lock.Unlock()
}()
}

func (m *manager) Wait() {
wait := false

m.lock.Lock()
if m.running > 0 {
m.waiting++
wait = true
}
m.lock.Unlock()

if wait {
<- m.wakeup
}
}

//// "main.go" //// some example usage

package main

import "fmt"
import "rand"
import "time"

import "./dispatch"

func main () {
w := dispatch.New()

for i := 0 ; i < 100 ; i++ {
c := i
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print( c , "\n" )
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print( c , " - second effect\n")
})
})
}

fmt.Print( "All Launched\n" )

w2 := dispatch.New()

for i := 0 ; i < 5 ; i++ {
c := i
w2.Go( func(){
w.Wait()
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print("[ " , c , "] This should happen
after the first set\n")
})
}

fmt.Print( "Second set all launched\n" )

w.Wait()

for i := 10 ; i < 15 ; i++ {
c := i
w.Go( func(){
time.Sleep( rand.Int63n( 1000000000 ) )
fmt.Print("[ " , c , "] reusing first queue\n")
})
}

fmt.Print( "Main thread past first set\n" )

w2.Wait()

fmt.Print( "Main thread past second set\n" )

w.Wait()

fmt.Print( "Main thread past reuse of first queue\n" )

}

roger peppe

unread,
Mar 9, 2010, 6:00:35 AM3/9/10
to Michael Speer, golang-nuts
this has been discussed before, in this thread:
http://groups.google.com/group/golang-nuts/browse_thread/thread/848a3f53fab0bfce/6e34a5ffbc807551

your code looks pretty good though. i've made a few comments
on your blog page.

Reply all
Reply to author
Forward
0 new messages