golang中channel的happened-before讲解


关于channel的happened-before有哪些

1. 第 n 个 send 一定 happened before 第 n 个 receive finished,无论是缓冲型还是非缓冲型的 channel。
2. 对于容量为 m 的缓冲型 channel,第 n 个 receive 一定 happened before 第 n+m 个 send finished。
3. 对于非缓冲型的 channel,第 n 个 receive 一定 happened before 第 n 个 send finished。
4. channel close 一定 happened before receiver 得到通知。

解释:
1. send不一定发生在recv之前,因为也可以先receive,然后goroutine被挂起,之后被sender唤醒,
无论如何,send一定发生在receive finished之前
2. 缓冲型channel,容量为m,第n+m个send发送之后的情形:
    如果第n个receive还没发生,这时候channel填满了,send就会被阻塞,
    当第n个receive接收完成后,sender goroutine会被唤醒,之后在继续发送过程
    也就是说第n个receive happened-before 第n+m个send finished
3. 第n个send如果被阻塞了,sender goroutine被挂起,第n个receive到来时,先与第n个send finished
    如果第n个send未被阻塞,说明第n个receive已经在那等着了,它不仅happened-before send finished
    而且还happened-before send
4. 先设置closed = 1,在唤醒等待的receiver, 并将零值拷贝给receiver

案例:
// 顺序一致性的内存模型,这是并发编程的基础

var ch = make(chan bool)
var msg string

func AGoroutine() {
	time.Sleep(time.Second)
	msg = "哈哈"
	<-ch
}

func main() {
	go AGoroutine()
	ch <- true
	fmt.Println(msg)  // 一定打印哈哈,为什么?
	// 因为 对于无缓冲型通道,第n个receive一定发生在第n个send finished之前
}
// 这里依赖的就是前面讲的happened-before 第一条,send一定发生在receive finished之前,
// 即 ch <- true 在 <-ch 之前

相关