go语言——select初窥(二)

706 阅读2分钟

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

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

selunlock

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循环的大括号一样(不恰当的比喻,不过之前操作系统的加锁解锁方式也遵循这种规律)

照例也有了

 if i > 0 && c == scases[lockorder[i-1]].c {
         continue // will unlock it on the next iteration
      }

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

selparkcommit

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可能有相同的通道,因此我们只有在通道的最后一个实例才可以解锁。