skynet.wakeup分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gneveek/article/details/78944812

官方文档:

skynet.wakeup(co) 唤醒一个被 skynet.sleep 或 skynet.wait 挂起的 coroutine 。在 1.0 版中 wakeup 不保证次序,目前的版本则可以保证。

唤醒流程

  1. 调用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
  1. 在当前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

猜你喜欢

转载自blog.csdn.net/gneveek/article/details/78944812