Two goroutines print 1..N in order, alternating odd and even
Implement printAlternating(n) that uses exactly two goroutines to print 1..n in order: one goroutine prints the odd numbers, the other the even, strictly alternating. Requirements: coordinate with channels — no shared counter, mutex, or busy-wait. The output must be in strict sequence, and the function must return only after all numbers are printed.
func printAlternating(n int) {
// your code here
}
Write the implementation.
Use two signal channels as a ping-pong: the odd goroutine waits on <-odd, prints, then signals even <- struct{}{}; the even goroutine mirrors it. main kicks off with odd <- struct{}{} and waits on a done channel the even goroutine closes after N. The hand-off enforces strict ordering with no shared state.
- ✗Reaching for a shared counter or mutex instead of channel hand-off
- ✗Assuming a single FIFO channel makes two consumers alternate deterministically
- ✗Thinking a
WaitGrouporders goroutine execution
- →Why does
struct{}{}make a good zero-size signal value on the channels? - →How does closing
donefrom the even goroutine cleanly stopmain?
Task
With two goroutines, print 1..N in order: one prints odd numbers, the other even, strictly alternating.
func main() {
odd := make(chan struct{})
even := make(chan struct{})
done := make(chan struct{})
const N = 10
go func() { // odd
for i := 1; i <= N; i += 2 {
<-odd
fmt.Println("odd:", i)
even <- struct{}{}
}
}()
go func() { // even
for i := 2; i <= N; i += 2 {
<-even
fmt.Println("even:", i)
if i < N {
odd <- struct{}{}
} else {
close(done)
}
}
}()
odd <- struct{}{} // kick off
<-done
}
How it works
Two unbuffered channels odd and even act as a "ping-pong" relay. Each goroutine blocks until it receives a signal, prints its number, and passes the signal to the other:
mainstarts the cycle by sending the first signal toodd;- the odd goroutine prints and signals
even, the even goroutine prints and signalsodd— and so on; - after the last number the even goroutine closes
done, andmainunblocks on<-done.
The value struct{}{} is zero-sized — a pure signal carrying no data. Strict ordering comes from the hand-off, with no shared mutable state and no locks.
⚠️ A classic channel-based synchronization problem, coordinating without shared memory.