Gaaaaaaaa
Gaaaaaaaa

Reputation: 167

How does go routine access local variable from calling function after function exited?

Fairly new to golang. I am a bit confused about go's variable scope. i have the following toy program

package main

import "sync"
import "time"
import "fmt"
import "math/rand"

func main() {
    go main_helper()
    time.Sleep(time.Duration(1000000) * time.Millisecond)

}
func main_helper() {
    rand.Seed(time.Now().UnixNano())

    count := 0
    finished := 0
    var mu sync.Mutex
    cond := sync.NewCond(&mu)

    for i := 0; i < 10; i++ {
        go func(i int) {
            vote := requestVote(i)
            mu.Lock()
            defer mu.Unlock()
            if vote {
                count++
            }
            fmt.Printf("cur_count: %d\n", count)
            finished++
            cond.Broadcast()
        }(i)
    }

    mu.Lock()
    for count < 5 {
        cond.Wait()
    }
    if count >= 5 {
        println("received 5+ votes!")
    } else {
        println("lost")
    }
    mu.Unlock()
    fmt.Printf("Exited main loop\n")

}

func requestVote(i int) bool {
    if i > 6 {
        time.Sleep(time.Duration(1000) * time.Millisecond)
    } else {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
    }
    fmt.Printf("go routine: %d requested vote\n", i)
    return true
}

When Running this in the Go playground i got the following output:

go routine: 0 requested vote
cur_count: 1
go routine: 6 requested vote
cur_count: 2
go routine: 1 requested vote
cur_count: 3
go routine: 4 requested vote
cur_count: 4
go routine: 2 requested vote
cur_count: 5
received 5+ votes!
Exited main loop
go routine: 3 requested vote
cur_count: 6
go routine: 5 requested vote
cur_count: 7
go routine: 7 requested vote
cur_count: 8
go routine: 8 requested vote
cur_count: 9
go routine: 9 requested vote
cur_count: 10

Which raise a question in that when main_helper() exit, why doesn't the local variable like count and mu go out of scope? Why are we still seeomg unfinished go routine updating the count variable correctly?

Upvotes: 1

Views: 2634

Answers (2)

Volker
Volker

Reputation: 42413

How does go routine access local variable from calling function after function exited?

Any compiler conforming to the Go Language Spec may use whatever technique its author choose to implement, e.g. putting all variables on the heap, not releasing memory at all, use reference counting or put just some variables on the stack.

Upvotes: -1

Burak Serdar
Burak Serdar

Reputation: 51512

It is the result of "escape analysis". The compiler realizes that the variable count escapes the function main_helper because it is used in the goroutine, so that variable is allocated on heap instead of on stack. In general, you can return pointers to local variables, and because of escape analysis, compiler allocates that variable on the heap, like:

type X struct {
   ...
}

func NewX() *X {
  return &X{}
}

This is a common constructor-like pattern to initialize structs. This code is equivalent to:

func NewX() *X {
  return new(X)
}

In your program, the count:=0 declaration is equivalent to:

count:=new(int)
*count=0

and the goroutine keeps a pointer to count. Same for finished.

Upvotes: 6

Related Questions