skynet的消息驱动 <2>

skynet创建的服务通过消息进行驱动,而消息的获取是通过队列。skynet有个全队列,其结构拥有一个头尾指针,并且有个自旋锁,防止push进来的数据过多。

// 全局队列:每个结点是一个消息队列指针,指向服务的消息队列
struct global_queue {
	struct message_queue *head;
	struct message_queue *tail;
	struct spinlock lock;
};

其中的message_queue则是消息队列,其结构如下,当创建一个服务的时候,会场景一个消息队列,并返回给ctx,创建成功后会将该消息队列push进全局消息队列中,这在上面也是有提到的。消息处理也可以看上一节的worker线程的处理。

struct message_queue {
	struct spinlock lock;
	uint32_t handle;				// 关联的服务句柄
	int cap;						// 队列容量
	int head;						// 队列头的位置:用数组模拟环形的队列
	int tail;						// 队列尾的位置
	int release;					// 标记该队列是否为释放状态,1为释放
	int in_global;					// 标识是否在全局队列中,见MQ_IN_GLOBAL
	int overload;					// 过载的消息数量 
	int overload_threshold;			// 过载的阀值,被初始化为MQ_OVERLOAD
	struct skynet_message *queue;	// 消息结构数组
	struct message_queue *next;		// 指向下一个消息队列 
};

那么消息是如何写到消息队列中的呢,即通过skynet.send()将消息push进的,流程如下:通过调用skynet.send(addr, type, …)进而调用lua-skynet的send_message函数。紧接着向服务压入该消息。根据句柄找到对应的ctx,然后将该ctx的消息队列以及消息作为参数调用skynet_mq_push,从而达到想改消息队列push消息的目的。次级消息队列的内容,并不是context结构的一部分(context只是引用了他的指针),因此,在一个服务执行callback的同时,其他服务(可能是多个线程内执行callback的其他服务)可以向它的消息队列里push消息,而mq的push操作,是加了一个自旋锁,以避免多个线程,同时操作一个消息队列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值