之前有用到合宙luat中的air202模块,热衷于Luat的消息发布和订阅的模式,便准备移植到我的程序中
先看效果
测试消息订阅发布的主函数
--main.lua
require("msg")
local x = 0
local y = 0
--订阅消息TEST_MSG
subscribe(
"TEST_MSG",
function(data)
y = y + 1
print("thsi is a test msg1", data.cnt, x, y, x + y, collectgarbage("count"))
end
)
--订阅消息TEST_MSG
subscribe(
"TEST_MSG",
function(data)
y = y + 1
print("thsi is a test msg2", data.cnt, x, y, x + y, collectgarbage("count"))
--在消息回调函数中发布消息
publish("TEST_MSG_MSG", {param = 12345})
end
)
--订阅消息TEST_MSG_MSG
subscribe(
"TEST_MSG_MSG",
function(data)
print("thsi is a test msg3", data.cnt, x, y, x + y, collectgarbage("count"))
end
)
--创建线程
task.run(
function()
local z = 0
while true do
x = x + 1
z = z + 1
publish("TEST_MSG", {param = 4322, cnt = z})
os.sleep(100)
end
end
)
运行结果:
3个消息事件循环执行,满足预期要求。
接下来就是msg.lua文件的实现了。该部分的代码基本上都是沿用 script_LuaTask 中的sys.lua文件中的代码。合宙Luat官网下载
------------------------------------------ LUA应用消息订阅/发布接口 ------------------------------------------
-- 订阅者列表
local subscribers = {}
--内部消息队列
local messageQueue = {}
--- 订阅消息
-- @param id 消息id
-- @param callback 消息回调处理
-- @usage subscribe("NET_STATUS_IND", callback)
function subscribe(id, callback)
if type(id) ~= "string" or (type(callback) ~= "function" and type(callback) ~= "thread") then
--log.warn("warning: sys.subscribe invalid parameter", id, callback)
return
end
if not subscribers[id] then
subscribers[id] = {}
end
subscribers[id][callback] = true
end
--- 取消订阅消息
-- @param id 消息id
-- @param callback 消息回调处理
-- @usage unsubscribe("NET_STATUS_IND", callback)
function unsubscribe(id, callback)
if type(id) ~= "string" or (type(callback) ~= "function" and type(callback) ~= "thread") then
--log.warn("warning: sys.unsubscribe invalid parameter", id, callback)
return
end
if subscribers[id] then
subscribers[id][callback] = nil
end
end
--- 发布内部消息,存储在内部消息队列中
-- @param ... 可变参数,用户自定义
-- @return 无
-- @usage publish("NET_STATUS_IND")
function publish(...)
table.insert(messageQueue, {...})
end
-- 分发消息
local function dispatch()
while true do
if #messageQueue == 0 then
break
end
local message = table.remove(messageQueue, 1)
if subscribers[message[1]] then
for callback, _ in pairs(subscribers[message[1]]) do
if type(callback) == "function" then
callback(table.unpack(message, 2, #message))
elseif type(callback) == "thread" then
--coroutine.resume(callback, table.unpack(message))
end
end
end
end
end
--启动消息轮询执行线程
task.run(
function()
print("启动线程 msg task > run")
while true do
dispatch()
os.sleep(10)
end
end
)
其中,添加了dispatch()函数的轮询机制。
注意:
- 我的多线程不是lua中的协同程序Coroutine。而是FreeRTOS操作系统所提供的多线程。
- os.sleep(ms)函数延时也必须是FreeRTOS中的延时函数,能够主动释放和切换FreeRTOS线程上下文。
- lua协同程序的主要功能是每个协程有自己的堆栈,只要自己主动切换和挂起时其他协程才会被执行。具体参考链接Lua Coroutine详解
- unpack()函数在5.1版本后修改成了table.unpack(),传入可变参数{...}的获取arg移除了,只能主动获取 local arg={...}