'Sync between 2 goroutines

My task is to sync 2 goroutines so the output should look like that:

foobarfoobarfoobarfoobar

.The issue is that when I call them they come out completely randomized. This is my code:

package main

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

type ConcurrentPrinter struct {
    sync.WaitGroup
    sync.Mutex
}


func (cp *ConcurrentPrinter) printFoo(times int) {
    cp.WaitGroup.Add(times)
    go func() {
        cp.Lock()
        fmt.Print("foo")
        cp.Unlock()
    }()
}
func (cp *ConcurrentPrinter) printBar(times int) {
    cp.WaitGroup.Add(times)
    go func() {
        cp.Lock()
        fmt.Print("bar")
        cp.Unlock()
    }()
}

func main() {
    times := 10
    cp := &ConcurrentPrinter{}

    for i := 0; i <= times; i++ {
        cp.printFoo(i)
        cp.printBar(i)
    }
    time.Sleep(10 * time.Millisecond)
}
go


Solution 1:[1]

As outlined in the comments, using goroutines may not be the best use case for what you are trying to achieve - and thus this may be an XY problem.

Having said that, if you want to ensure two independent goroutines interleave their work in an alternating sequence, you can implement a set of "ping-pong" mutexs:

var ping, pong sync.Mutex

pong.Lock() // ensure the 2nd goroutine waits & the 1st goes first

go func() {
    for {
        ping.Lock()
        foo()
        pong.Unlock()
    }
}()

go func() {
    for {
        pong.Lock()
        bar()
        ping.Unlock()
    }
}()

https://go.dev/play/p/VO2LoMJ8fek

Solution 2:[2]

Using channel:

func printFoo(i int, ch chan<- bool, wg *sync.WaitGroup) {
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Print("foo")
        ch <- true
    }()
}
func printBar(i int, ch chan<- bool, wg *sync.WaitGroup) {
    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Print("bar")
        ch <- true
    }()

}

func main() {
    times := 4
    firstchan := make(chan bool)
    secondchan := make(chan bool)
    var wg sync.WaitGroup
    for i := 0; i <= times; i++ {
        printFoo(i, firstchan, &wg)
        <-firstchan
        printBar(i, secondchan, &wg)
        <-secondchan
    }
    wg.Wait()
}

https://go.dev/play/p/MlZ9dHkUXGb

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 deepika azad