gochannelgoroutine

Race condition on go


When the code is ran time taken by attack() function is printed sometimes I know their is race condition when attack writes to channel and main reads it then main exits and doesn't wait for timer("attack") to execute

I am new to go:_)

package main

import (
    "fmt"
    "time"
)


func timer(funcName string) func(){
    startTime := time.Now()
    return func(){
        fmt.Printf("%s took %v time to run \n", funcName, time.Since(startTime))
    }
}

func main(){
    defer timer("main")()
    smokeSignal := make(chan bool)
    evilNinga := "Tommy"
    go attack(evilNinga, smokeSignal)
    fmt.Println(<-smokeSignal)
}

func attack(target string, smokeSignal chan<-bool){
    defer timer("attack")()
    time.Sleep(time.Second)
    fmt.Println("Throwing ninja stars at ", target)
    smokeSignal <- true
}

Can some tell how to handle this case, I want to print time taken by both the function, and use channels


Solution

  • Can some tell how to handle this case

    When main exits, the program is terminated, there is no graceful termination of concurrent goroutines (in many programs the non-main goroutines are ancillary "daemons" and not expected to shut down at all) so no guarantee extant defers will run. This is what occurs here: when you send the smoke signal, if the attack goroutine is descheduled then main can return before it gets re-scheduled, and thus defer never runs.

    There are a number of options to handle this issue, but all of them lead to basically the same thing: ensure you send on the channel after the function has run, which you can do by for instance (non-exhaustive)