Skynet 源码学习 -- 二级消息队列,Worker 工作线程池, Monitor 。

二级链表构造

简介

Skynet 为了消息处理实现了一个二级链表:

如下图所示 , 第一级链表是一个基于动态开辟节点实现的链表, 每一个节点对应一个服务单元,第二级链表是一个由数组实现的链表(需要时会以2倍的规模扩容),存储的是这个服务单元的所有待处理消息。
图示:

二级链表

功能点

  • 每个节点对应一个独立的服务单元。
  • 加锁
    • 一级链表自带自旋锁,但是仅仅在Push和Pop一个节点的时候加锁即可
    • 二级链表同样自带自旋锁,在Push和Pop一个Message的时候加锁即可
    • Message处理阶段无需加锁
  • 服务单元处理消息的回调函数无需线程安全
    • 每个节点被Worker线程通过Pop拿到节点后,在处理完它应该处理的Message之前不会将节点Push回一级链表, 故而单个服务单元的回调函数不会被多个Worker线程并发执行。
  • Message为空的节点不会被添加回一级链表。
  • Message由空转非空则添加回一级链表。

Worker线程

线程池果然是王道。

处理逻辑

  • 每个空闲Worker线程从一级链表中取出一个节点(一定是Message非空),处理之。
  • Worker线程检查节点对应的服务是否仍然存在,不存在则Release节点。存在则切换上下文,执行对应服务单元的包处理函数。
  • Worker检测是否是组播包,不是则Release包。
  • 为了防止有的Worker线程被饿死,Worker线程并不是一次性处理完一个节点的所有包,而是按照他自己的权重值,处理一部分(最少一个)包就返回。

Monitor

基本单元
struct skynet_monitor {
    int version;
    int check_version;
    uint32_t source;
    uint32_t destination;
};
工作逻辑
  • skynet_monitor_trigger自增version
  • 每个节点自带一个Monitor ,当它处理一个包的时候,就将这个包的信息利用 skynet_monitor_trigger 接口记录当前的source , destination
  • 当Message处理完就利用 skynet_monitor_trigger 接口置 source , destination 为0。
  • 有个每五分钟执行一次的Monitor线程会检测所有的节点,如果version 不等于check_version就用version 赋值check_version
  • 如果version 等于check_versiondestination 不为0 , 则认为这个节点死循环,删除之

解析:

每五分钟记录并同之前记录比对检测当前的version(处理的包个数X2), 其实就是一个假定 :在5-10分钟内无法执行完的Message解析函数就是死循环。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值