skynet skynet.fork()以及skynet.sleep()的工作流程

话不多说,先贴出测试代码

local skynet = require("skynet")

function task( )
	skynet.error("start sleep:",coroutine.running())  --被唤醒 然后sleep 5s
	skynet.sleep(500)
	skynet.error("end sleep:",coroutine.running())
end

skynet.start(function(  )
	skynet.error("start:",coroutine.running())
	local co = skynet.fork(task)  --fork 完了立即返回  co等待被唤醒执行task
	skynet.error("co status:",coroutine.status(co))  
end)

start函数的调用这里就不分析了,前面有介绍过,下面直接讨论skynet.fork、以及task的调用过程

//skynet.fork 调用
function skynet.fork(func,...)
	local args = table.pack(...)
	local co = co_create(function() //创建一个协程,相当于创建一个lua虚拟机
		func(table.unpack(args,1,args.n))
	end)
	table.insert(fork_queue, co) //将协程加到fork_queue队列中 
	return co
end

那fork_queue中挂起的协程什么时候被唤醒呢?
那就要回到 如下图
skynet skynet.fork()以及skynet.sleep()的工作流程_第1张图片coroutine_resume 回去唤醒对应的co,若这次用的是协程池里面的co,接下来分析一下过程

local function co_create(f)
	local co = table.remove(coroutine_pool)
	if co == nil then
		co = coroutine_create(function(...)
			f(...)
			while true do
				local session = session_coroutine_id[co]
				if session and session ~= 0 then
					local source = debug.getinfo(f,"S")
					skynet.error(string.format("Maybe forgot response session %s from %s : %s:%d",
						session,
						skynet.address(session_coroutine_address[co]),
						source.source, source.linedefined))
				end
				-- coroutine exit
				local tag = session_coroutine_tracetag[co]
				if tag ~= nil then
					if tag then c.trace(tag, "end")	end
					session_coroutine_tracetag[co] = nil
				end
				local address = session_coroutine_address[co]
				if address then
					release_watching(address)
					session_coroutine_id[co] = nil
				end

				-- recycle co into pool
				f = nil
				coroutine_pool[#coroutine_pool+1] = co
				-- recv new main function f
				f = coroutine_yield "SUSPEND" //接收到f  然后向下运行继续挂起 等待被唤醒,
				f(coroutine_yield())
			end
		end)
	else
		-- pass the main function f to coroutine, and restore running thread
		local running = running_thread
		coroutine_resume(co, f) //那么会跑到这里 唤醒co 传入f 
		running_thread = running
	end
	return co
end

那么此时将在上图的633行被唤醒 然后执行task 执行完task 回到while true 然后又跑到 f = coroutine_yield “SUSPEND” 给 633行返回参数 true,“SUSPEND”

接下来分析 skynet.sleep

local function suspend_sleep(session, token)
	local tag = session_coroutine_tracetag[running_thread]
	if tag then c.trace(tag, "sleep", 2) end
	session_id_coroutine[session] = running_thread
	assert(sleep_session[token] == nil, "token duplicative")
	sleep_session[token] = session //加到sleep_session队列中

	return coroutine_yield "SUSPEND" 
end

function skynet.sleep(ti, token)
	local session = c.intcommand("TIMEOUT",ti) //注册超时时间
	assert(session)
	token = token or coroutine.running()
	local succ, ret = suspend_sleep(session, token) //挂起在这里
	sleep_session[token] = nil
	if succ then
		return
	end
	if ret == "BREAK" then
		return "BREAK"
	else
		error(ret)
	end
end
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
			local tag = session_coroutine_tracetag[co]
			if tag then c.trace(tag, "resume") end
			session_id_coroutine[session] = nil
			suspend(co, coroutine_resume(co, true, msg, sz)) //在这里唤醒co 传入参数true, msg, sz
		end
	else
		local p = proto[prototype]
		if p == nil then
			if prototype == skynet.PTYPE_TRACE then
				-- trace next request
				trace_source[source] = c.tostring(msg,sz)
			elseif session ~= 0 then
				c.send(source, skynet.PTYPE_ERROR, session, "")
			else
				unknown_request(session, source, msg, sz, prototype)
			end
			return
		end

		local f = p.dispatch  --是否注册消息处理函数
		if f then
			local ref = watching_service[source]
			if ref then
				watching_service[source] = ref + 1
			else
				watching_service[source] = 1
			end
			local co = co_create(f)
			session_coroutine_id[co] = session
			session_coroutine_address[co] = source
			local traceflag = p.trace
			if traceflag == false then
				-- force off
				trace_source[source] = nil
				session_coroutine_tracetag[co] = false
			else
				local tag = trace_source[source]
				if tag then
					trace_source[source] = nil
					c.trace(tag, "request")
					session_coroutine_tracetag[co] = tag
				elseif traceflag then
					-- set running_thread for trace
					running_thread = co
					skynet.trace()
				end
			end
			suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz))) --解包数据
		else
			trace_source[source] = nil
			if session ~= 0 then
				c.send(source, skynet.PTYPE_ERROR, session, "")
			else
				unknown_request(session, source, msg, sz, proto[prototype].name)
			end
		end
	end
end

回到挂起的地方

function skynet.sleep(ti, token)
	local session = c.intcommand("TIMEOUT",ti)
	assert(session)
	token = token or coroutine.running()
	local succ, ret = suspend_sleep(session, token) //succ,ret = true,nil 执行下面代码然后执行sleep下面的代码后 返回true,SUSPEND
	sleep_session[token] = nil
	if succ then
		return
	end
	if ret == "BREAK" then
		return "BREAK"
	else
		error(ret)
	end
end    

你可能感兴趣的:(skynet框架分析)