The Go Memory Model

The Go Memory Model #

Initialization #

Program initialization runs in a single goroutine, but that goroutine may create other goroutines, which run concurrently.

If a package p imports package q, the completion of q’s init functions happens before the start of any of p’s.

The start of the function main.main happens after all init functions have finished.

image

在同一个文件中,常量、变量、init()main() 依次进行初始化。

initmain 两个函数的执行顺序:

  • 对同一个 Go 文件的 init() 调用顺序是从上到下的。
  • 对同一个 package 中的不同文件,将文件名按字符串进行“从小到大”排序,之后顺序调用各文件中的 init() 函数。
  • 对于不同的 package,如果不相互依赖的话,按照 main 包中 import 的顺序调用其包中的 init() 函数。
  • 如果 package 存在依赖,调用顺序为最后被依赖的最先被初始化,例如:导入顺序 main –> A –> B –> C,则初始化顺序为 C –> B –> A –> main,一次执行对应的 init 方法。

Goroutine #

Creation #

The go statement that starts a new goroutine happens before the goroutine’s execution begins.

go 语句的执行:新建 goroutine happens-before 开始执行 goroutine。

Destruction #

The exit of a goroutine is not guaranteed to happen before any event in the program.

goroutine 的退出不能保证 happens-before 于程序中的任何事件

Channel communication #

  1. A send on a channel happens before the corresponding receive from that channel completes.
  2. The closing of a channel happens before a receive that returns a zero value because the channel is closed.
  3. A receive from an unbuffered channel happens before the send on that channel completes.
  4. The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.

channel 的 happens-before 在Go的内存模型中的4种情况:

  1. channel 中的 send 操作(的开始) happens-before 于对应 receive 操作的结束。
  2. channel 的关闭 happens-before 于 receive 操作,receive 操作得到 0。
  3. unbuffered channel 中的 receive 操作(的开始) happens-before 于 send 操作的结束。
  4. 容量为 C 的 channel 的第 k 个 receive 操作,happens-before 于向该 channel 的第 k + C 个写 send 操作的完成。

unbuffered channel 时序保证:

image

buffered channel 时序保证:

image

Locks #

  1. For any sync.Mutex or sync.RWMutex variable l and n < m, call n of l.Unlock() happens before call m of l.Lock() returns.
  2. For any call to l.RLock on a sync.RWMutex variable l, there is an n such that the l.RLock happens (returns) after call n to l.Unlock and the matching l.RUnlock happens before call n+1 to l.Lock.

对于任意的 sync.Mutexsync.RWMutex 变量 l 并且 n < m,对第 n 个 l.Unlock() 的调用先行发生于第 m 个 l.Lock() 的返回。

一个 sync.RWMutex 变量 l,对于任何 l.RLock 的调用,存在一个 n,使得第 n 个 l.RLock 后来发生于第 n 个的 l.Unlock,同时该 RLock 所对应的 l.RUnlock 先行发生于第 n+1 个 l.Lock

Once #

A single call of f() from once.Do(f) happens (returns) before any call of once.Do(f) returns.

第一次 once.Do(f) 调用结束 happens-before 其他 once.Do(f) 的调用结束。

once.Do 在一个递归循环中,则会导致死锁 deadlock !

Once 保证函数 f() 只被调用一次。

func setup() {
	a = "hello, world"
	print("1111\n")
}

func doprint() {
	once.Do(setup)
	print(a)
}

func main() {
	go doprint()
	time.Sleep(2000 * time.Millisecond)
	go doprint()
	time.Sleep(2000 * time.Millisecond)
}

References #