官方文档:
skynet.wakeup(co)
唤醒一个被 skynet.sleep 或 skynet.wait 挂起的 coroutine 。在 1.0 版中 wakeup 不保证次序,目前的版本则可以保证。
唤醒流程
- 调用skynet.wakeup(co)后,会在wakeup_session表内插入一条数据,key=co,value=true.
function skynet.wakeup(co)
if sleep_session[co] and wakeup_session[co] == nil then
wakeup_session[co] = true
return true
end
end
- 在当前LuaState内,一旦回到主线程(main coroutine), 就会执行到suspend()函数(因为所有的yield都是suspend()的参数),而在suspend函数内,最终会调到
dispatch_wakeup
这个函数:
local function dispatch_wakeup()
local co = next(wakeup_session)
if co then
wakeup_session[co] = nil --清除表内关于此co的记录
local session = sleep_session[co]
if session then
session_id_coroutine[session] = "BREAK"
return suspend(co, coroutine_resume(co, false, "BREAK"))
end
end
end
虽然部分command会直接return而导致suspend
函数无法走到最后调用dispatch_wakeup
的地方,但是某个协程一定会让出执行权而最终走到command==”EXIT”这里,这时就会调到dispatch_wakeup
这里了。
dispatch_wakeup这个函数内会取出wakeup_session
表的一条数据,最终调用coroutine_resume(co, false, "BRADK")
来唤醒协程。
一些细节
在调用coroutine_resume
前,有这么一句:
session_id_coroutine[session] = "BREAK"
这里原来的值是co, 现在改成字符串”BREAK”, 只是为了打个标记而已,完全可以用任意的值,用处就是当系统的timeout模块给本服务发送唤醒消息时(一个空的RESPONSE),不要做任何处理,因为之前已经由skynet.wakeup唤醒过了。
看下代码:
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]
--这里判断下,如果是BREAK直接把session_id_coroutine表的记录删除,然后什么也不做
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
...
还有一个值得关注的地方:
suspend(co, coroutine_resume(co, false, "BREAK"))
这里唤醒协程的时候,传了两个参数 进去,是什么意思呢?
原来在skynet.sleep函数内,协程被唤醒后,会接受这两个返回值,并根据返回值来返回不同的信息给上层调用者:
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" --由skynet.wakeup唤醒,BREAK可以想象成有打断co了的睡眠:)
else
error(ret)
end
end