Go channel实现源码分析
go通道基于go的并发调度实现,本身并不复杂,go并发调度请看我的这篇文章:go并发调度原理学习
- type hchan struct {
- qcount uint // 缓冲区中已有元素个数
- dataqsiz uint //循环队列容量大小
- buf unsafe.Pointer // 缓冲区指针
- elemsize uint16 //元素大小
- closed uint32 //关闭标记,0没关闭,1关闭
- elemtype *_type //数据项类型
- sendx uint //发送索引
- recvx uint //接收索引
- recvq waitq //等待接收排队链表
- sendq waitq //等待发送排队链表
- lock mutex //锁
- }
- type waitq struct {
- first *sudog
- last *sudog
- }
- func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
- lock(&c.lock)
- if c.closed != {
- unlock(&c.lock)
- panic(plainError("send on closed channel"))
- }
- if sg := c.recvq.dequeue(); sg != nil {
- //缓冲区就是一个固定长度的循环列表
- //发送队列是一个双向链表,接在缓冲区的后面,整体是一个队列,保证先进先出
- //有接收者,并不是将当前要发送的数据直接发出,而是将缓冲区的第一个元素发送给接收者,同时将发送队列的第一个元素加入缓冲区刚出队列的位置
- send(c, sg, ep, func() { unlock(&c.lock) }, )
- return true
- }
- if c.qcount < c.dataqsiz {
- //缓冲区没有满,直接将要发送的数据复制到缓冲区,直接返回,
- qp := chanbuf(c, c.sendx)
- typedmemmove(c.elemtype, qp, ep)
- c.sendx++
- if c.sendx == c.dataqsiz {
- c.sendx =
- }
- c.qcount++
- unlock(&c.lock)
- return true
- }
- if !block {
- unlock(&c.lock)
- return false
- }
- //以上都是同步非阻塞的,ch <- 100直接返回
- //以下是同步阻塞
- //缓冲区满了,也没有接收者,通道将被阻塞,其实就是不执行当前G了,将状态改成等待状态
- gp := getg()
- mysg := acquireSudog()
- c.sendq.enqueue(mysg)
- goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, )
- //当G被唤醒,状态改成可执行状态,从这里开始继续执行
- releaseSudog(mysg)
- return true
- }
- func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
- func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
- lock(&c.lock)
- if sg := c.sendq.dequeue(); sg != nil {
- // Found a waiting sender. If buffer is size 0, receive value
- // directly from sender. Otherwise, receive from head of queue
- // and add sender's value to the tail of the queue (both map to
- // the same buffer slot because the queue is full).
- recv(c, sg, ep, func() { unlock(&c.lock) }, )
- return true, true
- }
- if c.qcount > {
- // Receive directly from queue
- qp := chanbuf(c, c.recvx)
- if ep != nil {
- typedmemmove(c.elemtype, ep, qp)
- }
- typedmemclr(c.elemtype, qp)
- c.recvx++
- if c.recvx == c.dataqsiz {
- c.recvx =
- }
- c.qcount--
- unlock(&c.lock)
- return true, true
- }
- if !block {
- unlock(&c.lock)
- return false, false
- }
- //以上同步非阻塞
- //以下同步阻塞
- gp := getg()
- mysg := acquireSudog()
- c.recvq.enqueue(mysg)
- //将当前G状态改成等待状态,停止调度
- goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, )
- //当前G被唤醒从这里继续执行
- mysg.c = nil
- releaseSudog(mysg)
- return true, !closed
- }
Go channel实现源码分析的更多相关文章
- Netty源码分析第1章(Netty启动流程)---->第3节: 服务端channel初始化
Netty源码分析第一章:Netty启动流程 第三节:服务端channel初始化 回顾上一小节的initAndRegister()方法: final ChannelFuture initAndRe ...
- NIO 源码分析(05) Channel 源码分析
目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- MyCat源码分析系列之——前后端验证
更多MyCat源码分析,请戳MyCat源码分析系列 MyCat前端验证 MyCat的前端验证指的是应用连接MyCat时进行的用户验证过程,如使用MySQL客户端时,$ mysql -uroot -pr ...
- gRPC源码分析0-导读
gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...
- dubbo源码分析6-telnet方式的管理实现
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储
前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,cli ...
- 最新版ffmpeg源码分析
最新版ffmpeg源码分析一:框架 (ffmpeg v0.9) 框架 最新版的ffmpeg中发现了一个新的东西:avconv,而且ffmpeg.c与avconv.c一个模样,一研究才发现是libav下 ...
- Java IO 之 FileInputStream & FileOutputStream源码分析
Writer :BYSocket(泥沙砖瓦浆木匠) 微 博:BYSocket 豆 瓣:BYSocket FaceBook:BYSocket Twitter ...
随机推荐
- Windows上安装配置SSH教程(2)——在Windows XP和Windows 10上安装并配置OpenSSH for Windows
知识点汇总:http://www.cnblogs.com/feipeng8848/p/8559803.html ------------------------ 安装方式有3种: (1)Windows ...
- jackson json转对象 json转集合 对大小写支持
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, isGetterVisibi ...
- 利用face_recognition库裁取人脸
from PIL import Image import face_recognition # Load the jpg file into a numpy array image = face_re ...
- Android 7.0 存储系统—Vold与MountService分析(一)(转 Android 9.0 分析)
Android的存储系统(一) 看了很长时间Vold存储模块的相关知识,也死扣了一段时间的Android源码,发现Android存储系统所涉及的函数调用,以及Kernel与上层之间的Socket传输真 ...
- es6学习笔记-proxy对象
前提摘要 尤大大的vue3.0即将到来,虽然学不动了,但是还要学的啊,据说vue3.0是基于proxy来进行对值进行拦截并操作,所以es6的proxy也是要学习一下的. 一 什么是proxy Prox ...
- 【重学计算机】操作系统D6章:并发程序设计
1. 并发程序的基本概念 程序顺序性 内部顺序性:CPU严格按照顺序执行指令 外部顺序性:程序员设计程序时往往用顺序设计的思想 顺序程序特性 程序执行的顺序性 计算环境的封闭性: 程序执行时犹如独占资 ...
- Ubuntu命令用法详解——curl命令
简介: cURL(CommandLine Uniform Resource Locator)是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行.它支持文件上传和下载,所以是综合传输工 ...
- WebApi管理和性能测试工具WebApiBenchmarks
说到WebApi管理和测试工具其实已经非常多的了,Postman.Swagger等在管理和维护上都非常出色:在性能测试方面也有不少的工具如:wrk,bombardier,http_load和ab等等. ...
- 前端笔记之NodeJS(二)路由&REPL&模块系统&npm
一.路由机制(静态资源文件处理) 1.1 Nodejs没有根目录 MIME类型:http://www.w3school.com.cn/media/media_mimeref.asp 在Apache中, ...
- 关于vue使用form上传文件
在vue中使用form表单上传文件文件的时候出现了一些问题,获取文件的时候一直返回null, 解决之后又出现发送到后台的file文件后台显示为空,解决源码 <template> <d ...