文章目录
在了解golang的内存模型后,对一些读写顺序如何保证有了了解,记录在这里
官网原文
内存模型
Happens before
Go内存操作中定义读写执行的顺序,没有明确的执行先后,则不能保证其结果顺序
对V的写入w可被读取r的条件
1.r 不happen before w
2.没有其他的写入w’ happen after w 且 happen before r
保证对V的写入w是读取r唯一可获取的条件(无读写并发)
1.w happen before r
2.其他的写入w happen after r 或 happen before w
变量初始化是内存模型中的写操作
大于单个机器字长的读写,表现为多个机器字长大小的无序读写操作(机器字长是指计算机进行一次整数运算所能处理的二进制数据的位数)
Synchronization 同步
初始化
- 包p import 包q,q的init happen before p的
- main.main happen after 所有包init函数
goroutine
- go创建goroutine happens before 该goroutine执行;
- goroutine的退出不保证happens before 其他执行
channel
- channel的发送 happens before 该channel的读取完成
- channel的关闭 happens before 该channel的0值读取
- 无缓冲channel的读取 happens before 该channel的发送的完成
1
2
3
4
5
6
7
8
9
10
11
12var c = make(chan int)
var a string
func f() {
a = "hello, world"
<-c //先于 `c <- 0`
}
func main() {
go f()
c <- 0
print(a)
} - 容量为c的channel,第k次读取 happens before 第
k+c
次发送的完成1
2
3
4
5
6
7
8
9
10
11
12
13//多用于limit 并发
var limit = make(chan int, 3)
func main() {
for _, w := range work {
go func(w func()) {
limit <- 1
w()
<-limit
}(w)
}
select{}
}sync
- sync.Mutex or sync.RWMutex中,若
n < m
,则第n次Unlock()
happens before 第m次Lock()
两个lock之间必须有一个unlock,否则会在lock处无限等待
读写锁: 读-读能共存,读-写不能共存,写-写不能共存1
2
3
4
5
6
7
8
9
10
11
12
13
14var l sync.Mutex
var a string
func f() {
a = "hello, world"
l.Unlock()
}
func main() {
l.Lock()
go f()
l.Lock() //此处保证goroutine先执行
print(a)
} - 在sync.RWMutex中,第n次
Unlock()
happens beforeRLock()
,对应的RUnlock()
happens before 第n+1
次Lock()
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.
1
2
3
4
5//顺序就是
l.UnLock()
l.RLock()
l.RUnlock()
l.Lock() - 单次once.Do(f)调用中f函数的返回 happens before 其他所有 once.Do(f)调用的返回
就是同时调用once.Do(f),只有第一次调用会执行,其他会阻塞直到
f()
返回。
如有疑问,请文末留言交流或邮件:newbvirgil@gmail.com 本文链接 : https://newbmiao.github.io/2018/02/06/go-memory-model.html