cloudwu/ltask

独占线程处理sending队列时,同一个服务的消息会不会出现乱序

sniper00 opened this issue · 7 comments

  1. 假如 sending 队列要发送消息到 服务 S ,顺序是:a,b,c,d,e
  2. 发送 a 时,S blocked, a 被放到 e 后边
  3. 发送 b 时,S 变为非blocked, 这样 b 就先于 a 被处理了

queue_push_ptr(sending, msg);

static void
dispatch_exclusive_sending(struct exclusive_thread *e, struct queue *sending) {
	struct ltask *task = e->task;
	struct service_pool *P = task->services;
	int len = queue_length(sending);
	int i;
	for (i=0;i<len;i++) {
		struct message *msg = (struct message *)queue_pop_ptr(sending);
		switch (service_push_message(P, msg->to, msg)) {
		case 0 :	// succ
			break;
		case 1 :	// block, push back
			queue_push_ptr(sending, msg);
			break;
		default :	// dead, delete message
			// todo : report somewhere or release object in message
			message_delete(msg);
			break;
		}
		if (service_status_get(P, msg->to) == SERVICE_STATUS_IDLE) {
			debug_printf(e->logger, "Service %x is in schedule", msg->to.id);
			service_status_set(P, msg->to, SERVICE_STATUS_SCHEDULE);
			schedule_back(task, msg->to);
		}
	}
}

这是设计之中的

解释一下:当 A 向 B 和 C 发消息时,发出的次序和 B C 收到(处理)的次序无关。

所谓消息的次序,只在发送者和接收者固定对上才有意义。

如果向同一个服务发送需要保证次序,可以用普通的 send 而不要用批量 send 。

那这个批量send主要用于哪些场景?

又想了一下。目前 timer 服务是没有问题的;但如果做网络服务有问题。我今天改一下。

我加了一个机制来保证同一个服务上的消息次序:当一个服务首次被发现阻塞后,这一批的所有发向该服务的消息都不再发送。

因为服务的消息队列被阻塞是一个罕见状态,所以我用了一个简单的 O(n) 的数据结构来处理这种情况。此处 n 是当前发送队列中处于阻塞状态的服务数量。n 通常不会太大。绝大部分时候 n == 0 。

嗯,看样子可以解决这个问题