skynet学习笔记 源码之sknyet_mq消息队列

前言

消息队列是skynet非常核心的东西,每个context都会一个次级消息队列,次级消息队列会链接到全局队列,等待worker线程的处理。

全局队列

全局队列是一个单向链表,记录头尾位置,尾部入头部出。

struct global_queue {
	struct message_queue *head;
	struct message_queue *tail;
	struct spinlock lock;
};

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)
}

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;
}

次级消息队列

全局消息队列的结点类型为message_queue,也就是次级消息队列,里面链接的skynet_message

struct message_queue {
	struct spinlock lock;
	uint32_t handle;
	int cap;
	int head;
	int tail;
	int release;
	int in_global;
	int overload;
	int overload_threshold;
	struct skynet_message *queue;
	struct message_queue *next;
};

次级消息队列实际上是一个动态分配内存大小的数组,初始化cap数据大小为64,head,tail相对于快慢指针的应用。head记录头消息位置,tail记录下一个空位置,当push一个消息后,tail位置等于head位置,说明数组消息缓存已经满了,mq会扩容到当前大小的两倍,并且接手旧数据的消息。

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)
}

static void
expand_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;
}

int
skynet_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 empty
		q->overload_threshold = MQ_OVERLOAD;
	}

	if (ret) {
		q->in_global = 0;
	}
	
	SPIN_UNLOCK(q)

	return ret;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Skynet是一个开源的分布式游戏服务器引擎,它由前后端源码构成。前端源码主要负责处理客户端与服务器之间的交互逻辑,而后端源码则负责处理服务器端的逻辑处理和数据存储。 前端源码中,主要包含了游戏客户端的逻辑处理和界面展示。它通常使用一种编程语言(如C++、Lua等)来编写,并提供了一些接口用于与后端服务器进行通信。在游戏中,前端源码会根据玩家的操作进行界面的展示,同时将用户的输入发送给后端服务器,以便后端进行相应的逻辑处理。 后端源码Skynet的核心,它负责处理游戏服务器的逻辑处理和数据存储。后端源码通常使用一种高性能的编程语言(如C++、Java等)来编写,并提供了一系列的模块用于处理不同的逻辑需求,如游戏逻辑模块、网络模块、数据库模块等。其主要功能包括接收前端发送的请求、进行逻辑处理、更新数据状态等。同时,后端源码还可以支持多个服务器之间的互联,以实现分布式的游戏服务器集群。 Skynet的前后端源码的设计目标是提供一个高性能、易扩展的游戏服务器引擎,以满足不同规模游戏项目的需求。通过前后端源码的配合,Skynet可以快速构建起一个稳定可靠的游戏服务器系统,并支持大规模的并发用户请求处理。同时,通过源码的开源,让开发者可以根据自身需求进行二次开发和定制,以满足不同游戏项目的特定需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值