版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gneveek/article/details/78944807
官方文档
skynet.sleep(ti) 将当前 coroutine 挂起 ti 个单位时间。一个单位是 1/100 秒。它是向框架注册一个定时器实现的。框架会在 ti 时间后,发送一个定时器消息来唤醒这个 coroutine 。这是一个阻塞 API 。它的返回值会告诉你是时间到了(返回nil),还是被 skynet.wakeup 唤醒 (返回 “BREAK”)。
Code
function skynet.sleep(ti)
local session = c.intcommand("TIMEOUT",ti)
assert(session)
local succ, ret = coroutine_yield("SLEEP", session)
sleep_session[coroutine.running()] = nil
if succ then
return
end
if ret == "BREAK" then
return "BREAK"
else
error(ret)
end
end
c.intcommand(“TIMEOUT”,ti)会调到C里面的这个函数。
static const char *
cmd_timeout(struct skynet_context * context, const char * param) {
char * session_ptr = NULL;
int ti = strtol(param, &session_ptr, 10);
int session = skynet_context_newsession(context);
skynet_timeout(context->handle, ti, session);
sprintf(context->result, "%d", session);
return context->result;
}
这里会调用skynet_timeout注册一个定时器,当时间到后,就会给context->handle
这个服务发送一个类型为PTYPE_RESPONSE
的消息来唤醒它。代码如下:
int
skynet_timeout(uint32_t handle, int time, int session) {
if (time <= 0) {//如果时间<=0,直接发消息
struct skynet_message message;
message.source = 0;
message.session = session;
message.data = NULL;
message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;
if (skynet_context_push(handle, &message)) {
return -1;
}
} else {//添加定时器
struct timer_event event;
event.handle = handle;
event.session = session;
timer_add(TI, &event, sizeof(event), time);
}
return session;
}
时间到后会调到下面这个C函数:
static inline void
dispatch_list(struct timer_node *current) {
do {
struct timer_event * event = (struct timer_event *)(current+1);
struct skynet_message message;
message.source = 0;
message.session = event->session;
message.data = NULL;
message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;
skynet_context_push(event->handle, &message);
struct timer_node * temp = current;
current=current->next;
skynet_free(temp);
} while (current);
}
可以看到,给注册这个定时器的服务发了个PTYPE_RESPONSE的消息。
之后就跟skynet.call + skynet.ret的流程一样了:
local function raw_dispatch_message(prototype, msg, sz, session, source)
-- skynet.PTYPE_RESPONSE = 1, read skynet.h
if prototype == 1 then
local co = session_id_coroutine[session]
if co == "BREAK" then
session_id_coroutine[session] = nil
elseif co == nil then
unknown_response(session, source, msg, sz)
else
session_id_coroutine[session] = nil
suspend(co, coroutine_resume(co, true, msg, sz))
end
else
...
消息回调这边特殊处理PTYPE_RESPONSE的消息,调用coroutine.resume唤醒协程。
可以看到上面那段代码里面有个 if co == "BREAK"
的判断,这是干嘛的呢?
其实云风文档里已经说了,是skynet.wakeup搞的鬼。
详细分析请看:skynet.wakeup分析