Search code examples
loopsgogoroutine

Should I pass request object to goroutine in blocking for-select loop coming from channel?


I have the following for-select structure in code:

go func(runCh chan Caller, shutdownSignal chan bool) {
        for {
            select {
            case request := <-runCh:
                go func() {
                    w.Run(&request)
                }()
            case <-shutdownSignal:
                w.Shutdown()
                return
            }
        }
    }(runCh, shutdownCh)

Will I have some problems with this part:

case request := <-runCh:
    go func() {
        w.Run(&request)
    }()

?

If yes, then why?

In other words - does Using goroutines on loop iterator variables part of Common Mistakes also apply to my case and why it does/does not apply here?


Solution

  • No (does not apply here), you have new variable (memory address) on each loop iteration:

     case request := <-runCh:
    

    Because this := creates new variable distinct from previous one, proof:

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        runCh := make(chan int, 2)
        runCh <- 1
        runCh <- 2
        for i := 1; i <= 2; i++ {
            select {
            case request := <-runCh:
                go func() {
                    fmt.Println(request, &request)
                    time.Sleep(200 * time.Millisecond)
                    fmt.Println(request, &request)
    
                }()
            }
        }
        time.Sleep(500 * time.Millisecond)
    
    }
    

    Output (the address of request in each loop iteration is different):

    1 0xc0000b8000
    2 0xc0000b8008
    1 0xc0000b8000
    2 0xc0000b8008
    

    See: 0xc0000b8000 != 0xc0000b8008