设为首页 加入收藏

TOP

GO 语言中 chan 的理解(二)
2023-07-23 13:25:05 】 浏览:73
Tags:chan
p; // 检查 chan 是否已经关闭     if c.closed != 0 && c.qcount == 0 {         return false, false     }     // 计算接收位置     i := c.recvx     // 如果队列中没有数据,需要阻塞等待     for c.qcount <= 0 {         if !block {             return false, false         }         gopark(chanparkcommit, unsafe.Pointer(c), "chan receive", traceEvGoBlockRecv, 1)     }     // 从队列中取出数据     qget(c, i, ep)     // 更新接收位置     c.recvx++     // 更新队列中的元素数量     c.qcount--     return true, true }

chan 是如何实现多个 gorouting 并发安全访问的?

如上 hchan 结构中的 recvq 和 sendq 分别表示接收等待队列和发送等待队列,它们的定义如下:

type waitq struct {
    first *sudog // 等待队列的第一个元素
    last  *sudog // 等待队列的最后一个元素
}

sudog 表示等待队列中的一个元素,它的定义如下:

type sudog struct {
    // 等待的 goroutine
    g *g
    // 是否是 select 操作
    isSelect bool
    // 等待队列中的下一个元素
    next *sudog
    // 等待队列中的上一个元素
    prev *sudog
    // 等待的元素
    elem unsafe.Pointer
    // 获取锁的时间
    acquiretime int64
    // 保留字段
    release2 uint32
    // 等待的 ticket
    ticket uint32
    // 父 sudog
    parent *sudog
    // 等待链表
    waitlink *sudog
    // 等待链表的尾部
    waittail *sudog
    // 关联的 chan
    c *hchan
    // 唤醒时间
    releasetime int64
}

当 chan 的队列已满或为空时,当前 goroutine 会被加入到发送等待队列或接收等待队列中,并释放锁。当另一个 goroutine 从 chan 中取出数据或向 chan 发送数据时,它会重新获取锁,并从等待队列中取出一个 goroutine,将其唤醒。这样,多个 goroutine 就可以通过等待队列来实现并发访问 chan。

sudog 是 Go 中非常重要的数据结构,因为 g 与同步对象关系是多对多的。

一个 g 可以出现在许多等待队列上,因此一个 g 可能有很多sudog:在 select 操作中,一个 goroutine 可以等待多个 chan 中的任意一个就绪, sudog 中的 isSelect 字段被用来标记它是否是 select 操作。当一个 chan 就绪时,它会唤醒对应的 sudog,并将其从等待队列中移除。如果一个 sudog 是 select 操作,它会在唤醒后返回一个特殊的值,表示哪个 chan 就绪了

多个 g 可能正在等待同一个同

首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go 语言 context 都能做什么? 下一篇提升性能的利器:深入解析Section..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目