How to make goroutines talk to each other using Channels

Issue

I am new to Golang and am trying to use goroutines so that they can talk among them. I have some code which starts up a goroutine which has operation1, I call it to dance. When it finishes, it signals another goroutine which performs another operation2, let’s say sleep.

You can pass a force dance parameter to the dance goroutine but if it is already in the dance state, it would sleep.

package main

import (
    "fmt"
    "time"
)

func main(){
    test("notdancing", true)
    time.Sleep(10*time.Second)
}
func dance()error{
    fmt.Println("Tapping my feet")
    time.Sleep(10*time.Second)
    return nil
}
func test(status string, forceDance bool) {

This does not work when

   //startSleep := make(chan bool)

Why does a channel need to be provided a buffer length to make it work? I tried without the buffer length but it says all goroutines are asleep if I don’t pass 1 as the second parameter.

    startdance := make(chan bool, 1)
    startSleep := make(chan bool, 1)

    if status == "dancing" && forceDance {
        select {
        case startSleep <-true:
            fmt.Println("Would start to sleep now")
        default:
            fmt.Println("Sleep Already started. No need to force")
        }
    }

    if status != "dancing" {
        fmt.Println("Startingdance")
        startdance <- true
    }

    go func() {
        <-startdance
        err := dance()
        if err == nil {
            select {
            case startSleep <- true:
                fmt.Println("Starting Sleeping, dancing completed")
            default:
                fmt.Println("Already started Sleeping")
            }
        } else {
            fmt.Println("Not in a mood to dance today")
        }
    }()

    go func() {
        <-startSleep
        if forceDance {
            fmt.Println("Force sleep because forcing to dance while already dancing")
        }
    }()

}

I would highly appreciate any corrections to the code as well as the pitfalls of using this approach.

Solution

in case of Unbuffered Channel (when size is not specified) it can’t hold a value as it has no size. therefore a reader has to be present at the time of writing/transmiting the data through the channel or else it will be blocking the call.

func main() {
    startDance := make(chan bool)
    startDance <- true
}

But when you specify a size in the above code (say 1) then it won’t be a deadlock as it will have space to hold the data. ((https://robertbasic.com/blog/buffered-vs-unbuffered-channels-in-golang/) .)(https://www.golang-book.com/books/intro/10) you could check out the above website’s to get a better understanding about channels and concurrency

package main

import (
    "fmt"
    "time"
)

func main() {
    startDance := make(chan bool)
    startSleep := make(chan bool)
    forceSleep := make(chan bool)
    go startDance1(startDance, forceSleep, startSleep)
    go performSleep(startSleep, startDance)
    startDance <- true
    fmt.Println("now dance is started ")
    forceSleep <- true
    select {}
}

func startDance1(startDance chan bool, forceSleep chan bool, startSleep chan bool) {

    fmt.Println("waiting to start dance")
    select {
    case <-startDance:
        fmt.Println("staring dance")
    }

    for {
        select {
        case <-startDance:
            fmt.Println("starting dance")
        case <-forceSleep:
            fmt.Println("aleardy dancing going to sleep")
            select {
            case startSleep <- true:

            default:
            }
        default:
            //this is just to show working this
            // i added default or else this will go into deadlock
            fmt.Println("dancing")
            time.Sleep(time.Second * 1)
        }
    }
}

func performSleep(startSleep chan bool, startDance chan bool) {
    select {
    case <-startSleep:
        fmt.Println("staring sleep")
    }
    fmt.Println("sleeping for 5 seconds ")
    time.Sleep(time.Second * 5)
    select {
    case startDance <- true:
        fmt.Println("started dance")
    default:
        fmt.Println("failed to start dance ")
    }
}

Above code is a minor improvement over yours (i tried to make it according to your requirements). I would suggest you go through some books to get to know more about go concurrency (https://www.golang-book.com/books/intro/10_

Answered By – Siva Guru

Answer Checked By – Mary Flores (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.