go语言——select初窥(二)

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」。

上篇文章讲了sellock,接下来接着继续看

selunlock

1
2
3
4
5
6
7
8
9
go复制代码func selunlock(scases []scase, lockorder []uint16) {
for i := len(lockorder) - 1; i >= 0; i-- {
c := scases[lockorder[i]].c
if i > 0 && c == scases[lockorder[i-1]].c {
continue // will unlock it on the next iteration
}
unlock(&c.lock)
}
}

首先第一个看到的问题就是相对于sellock,他的遍历顺序恰恰相反,这里猜测是像for循环的大括号一样(不恰当的比喻,不过之前操作系统的加锁解锁方式也遵循这种规律)

照例也有了

1
2
3
go复制代码 if i > 0 && c == scases[lockorder[i-1]].c {
continue // will unlock it on the next iteration
}

这部分当然也是为了防止重复解锁,不过作者在注释中特意强调了一定要注意不要重复解锁,因为一个通道在被解锁后可能就被释放了。

selparkcommit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
go复制代码func selparkcommit(gp *g, _ unsafe.Pointer) bool {

gp.activeStackChans = true

atomic.Store8(&gp.parkingOnChan, 0)

var lastc *hchan
for sg := gp.waiting; sg != nil; sg = sg.waitlink {
if sg.c != lastc && lastc != nil {
unlock(&lastc.lock)
}
lastc = sg.c
}
if lastc != nil {
unlock(&lastc.lock)
}
return true
}

gp.activeStackChans = true,第一行就看不懂了,查了下gp可以理解为是一个stack,activeStackChans表示有未锁定的通道指向这个协程的堆栈,当他为true的时候,代表如果进行堆栈复制的话需要我们先锁通道再进行堆栈复制。

atomic.Store是往第一个参数里写入第二个参数的值,是一个原子操作。store8代表参数类型为unit8。

ParkingOnChan 表示 goroutine 即将停在 chansend 或 chanrecv 上。 用于表示堆栈收缩的不安全点。 它是一个布尔值,但会原子的更新。

一旦我们解锁这个通道,该通道里任何sudog中的字段都有可能会更改,由于多个sudog可能有相同的通道,因此我们只有在通道的最后一个实例才可以解锁。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%