Printing Issue with Concurrent Routines in Go

Issue

I have three concurrent routines like this,

func Routine1() {

Print (value a, value b, value c)
Print (value a, value b, value c)
Print (value a, value b, value c)

}

func Routine2() {
Print (value e, value f, value g)
Print (value e, value f, value g)
Print (value e, value f, value g)
}
func Routine3() {
Print (value x, value y, value z)
Print (value x, value y, value z)
Print (value x, value y, value z)
}

func main() {
go Routine1(command12, response12, command13, response13)
go Routine2(command12, response12, command23, response23)
Routine3(command13, response13, command23, response23)
}

Now what problem I am facing is, sometimes it will happen that, as the result of three concurrent routines, sometimes the print statement is not executing properly means not printing whole, there is some thing inserted by another print. For example, Print (value a, value b, value c) of routine 1 gives output like value a, value b, value g where value g is inserted by routine 2. Can anybody suggest me, how can I stop it ? I have tried sync-mutex procedure. However may be as my code is too long and may be I can not put lock-unlock in a right way, so it is giving a deadlock error. Can anybody suggest me how can I implement those in a simple way or in a less risky sync-mutex procedure.

More info about this problem of mine can be found here.

Solution

Printing as you describe it is not an atomic operation. Instead of using mutexes, try the Go way. Pass a channel into each goroutine which accepts a string. Every time you want to print something, just send the string into that channel.

A separate goroutine does nothing more than read from that channel and prints whatever comes out. This way there is no need for locks.

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(2) // 2 routines we need to wait for.

    stdout := make(chan string)

    go routine1(&wg, stdout)
    go routine2(&wg, stdout)
    go printfunc(stdout)

    wg.Wait()

    close(stdout)
}

func routine1(wg *sync.WaitGroup, stdout chan<- string) {
    defer wg.Done()

    stdout <- "first print from 1"
    // do stuff
    stdout <- "second print from 1"
}

func routine2(wg *sync.WaitGroup, stdout chan<- string) {
    defer wg.Done()

    stdout <- "first print from 2"
    // do stuff
    stdout <- "second print from 2"
}

func printfunc(stdout <-chan string) {
    for {
        select {
        case str := <- stdout:
            fmt.Println(str)
        }
    }
}

Answered By – jimt

Answer Checked By – Katrina (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.