skynet底层源码阅读(2)-消息队列
来源:互联网 发布:excel不显示重复数据 编辑:程序博客网 时间:2024/05/22 13:34
skynet的c底层源码在Skynet-src中。一开始,我们首先从一些简单的组件看起。skynet主要用于处理服务间的消息,每个服务都有存放消息的队列。在Skynet_mq.h中,定义了消息队列中的消息类型:
// sky_net 内部的消息struct skynet_message {uint32_t source;//消息源的句柄int session;//用来做上下文的标识void * data;//消息指针size_t sz;//消息长度,消息的请求类型定义在高八位};
skynet的每一个服务都有自己的编号,source就表示该消息来自哪个编号的服务。
在Skynet_mq.c中,定义了消息队列结构体:
struct message_queue {//锁struct spinlock lock; uint32_t handle; //所属服务handleint cap; //容量int head; //对头 int tail; //队尾//消息队列释放标记,当要释放一个服务的时候,清理标记//不能立即释放该服务对应的消息队列(有时候工作线程还在操作mq),就需要设置一个标记,标记是否可以释放int release; //该消息队列是否在全局的消息队列中int in_global;int overload;int overload_threshold;//消息队列 利用数组实现的一个循环队列 struct skynet_message *queue;//为了将该队列串联到全局的二维的消息队列中struct message_queue *next;};queue指向存放数据的内存,该结构体主要管理了一个循环队列,实现比较简单。其余的操作无非就是将消息加入队列,弹出队列。
//将消息加入到message_queue 的 queue的尾部void skynet_mq_push(struct message_queue *q, struct skynet_message *message) {assert(message);SPIN_LOCK(q)q->queue[q->tail] = *message;if (++ q->tail >= q->cap) {q->tail = 0;}//扩容if (q->head == q->tail) {expand_queue(q);}if (q->in_global == 0) {//标记为在全局的二维消息队列中q->in_global = MQ_IN_GLOBAL;//将消息队列加入到全局的消息队列中 skynet_globalmq_push(q);}SPIN_UNLOCK(q)}
在消息队列容量不够的时候,会扩展容量:
//将消息队列message_queue 的queue容量扩大两倍static voidexpand_queue(struct message_queue *q) {struct skynet_message *new_queue = skynet_malloc(sizeof(struct skynet_message) * q->cap * 2);int i;//复制以前的for (i=0;i<q->cap;i++) {new_queue[i] = q->queue[(q->head + i) % q->cap];}q->head = 0;q->tail = q->cap;q->cap *= 2;//销毁以前的 skynet_free(q->queue);q->queue = new_queue;}
//从循环消息队列message_queue中取出一条消息struct skynet_message message是传出参数intskynet_mq_pop(struct message_queue *q, struct skynet_message *message) {int ret = 1;//加锁SPIN_LOCK(q)//如果循环消息队列中存在消息if (q->head != q->tail) {//传出一个消息*message = q->queue[q->head++];ret = 0;int head = q->head;int tail = q->tail;int cap = q->cap;if (head >= cap) {q->head = head = 0;}//获得循环消息队列中的消息个数int length = tail - head;if (length < 0) {length += cap;}while (length > q->overload_threshold) {q->overload = length;q->overload_threshold *= 2;}} else {// reset overload_threshold when queue is emptyq->overload_threshold = MQ_OVERLOAD;}//如果循环消息队列中没有消息,=0标记该循环队列没有在全局的二维消息队列中if (ret) {q->in_global = 0;}SPIN_UNLOCK(q)return ret;}为了统一管理每个服务的消息队列,skynet将没有服务的消息队列链接起来,形成一个二级的消息队列:
struct global_queue {struct message_queue *head;struct message_queue *tail;//锁struct spinlock lock;};
//全局变量static struct global_queue *Q = NULL;
也有对全局消息队列的添加与移除操作:
//将消息队列插入到全局消息队列中void skynet_globalmq_push(struct message_queue * queue) {struct global_queue *q= Q;SPIN_LOCK(q)assert(queue->next == NULL);//插入到尾部if(q->tail) {q->tail->next = queue;q->tail = queue;} else {//第一次插入的时候q->head = q->tail = queue;}SPIN_UNLOCK(q)}
//从全局队列中 移除一个消息队列message_queue,从头部移除,返回该指针struct message_queue * skynet_globalmq_pop() {struct global_queue *q = Q;SPIN_LOCK(q)struct message_queue *mq = q->head;//从头部移除if(mq) {q->head = mq->next;if(q->head == NULL) {assert(mq == q->tail);q->tail = NULL;}mq->next = NULL;}SPIN_UNLOCK(q)return mq;}
其余的就是一些创建和销毁的函数了,实现比较简单。整体结构如图:
阅读全文
0 0
- skynet底层源码阅读(2)-消息队列
- skynet底层源码阅读(1)
- skynet消息队列源码分析
- skynet底层源码阅读(3)-模块管理
- skynet底层源码阅读(4)-服务管理
- skynet底层源码阅读(5)-服务
- skynet底层源码阅读(6)-定时器
- skynet底层源码阅读(7)-网络服务
- skynet底层源码阅读(8)-启动流程
- skynet源码分析(2)--消息队列mq
- skynet源码学习 - 从全局队列中弹出/压入一个消息队列过程
- Skynet 源码学习 -- 二级消息队列,Worker 工作线程池, Monitor 。
- freeDiameter源码阅读之消息队列和消息处理流程
- skynet消息及一些源码解析
- skynet源码分析(5)--消息机制之消息处理
- skynet源码分析(6)--消息机制之消息分发
- ArrayList增删底层源码阅读
- 云风 Skynet 阅读笔记
- spring中的bean
- 如何实现类似锚链接的导航联动效果
- 法律人工智能十大趋势(下)
- 百度云VS阿里云 云计算到底到了什么时代?
- 写测试感悟,获取测试学习视频资料
- skynet底层源码阅读(2)-消息队列
- could not find developer disk image
- Hibernate反向工程出现BigDecimal类型解决办法
- 醒醒吧!深度学习不是AI的未来
- TCP连接释放的四次挥手过程?
- 阿里巴巴摘得LSVC桂冠 打造领先AI视频技术
- 贺!RocketMQ成为Apache软件基金会顶级开源项目
- 对待棘手bug,新手与大牛的差距在哪里?
- AWK