基于Lua协程的简单任务管理

高效的嵌入式系统功能开发

在嵌入式Linux系统开发过程中,开发人员常常使用脚本语言来实现一些系统功能,例如python/Shell等,以提高一些系统配置、控制、监测方面开发的效率。基于脚本的系统功能开发,是可行的;主要因为与业务相关的应用相比,系统相关的功能,没有高并发、低延迟等实时性的要求。而且一些系统服务在运行过程中,其对系统做出的调整,常常不是瞬时的;例如压缩一个日志文件、操作某个网口的网络配置等,都需要持续一段时间(才能完成),这些功能的开发与脚本的功能特点符合得比较好。因此,使用高级的、抽象的脚本语言来完成嵌入式系统的开发,是开发效率和运行稳定性的最优的选择。

然而,对于python脚本而言,其对系统配置要求高,可能不适合一些系统资源受限的嵌入式设备;而Shell脚本语言表达能力比较低,不适合完成一些比较复杂的功能模块。这样就需要一个折中的脚本语言,即要兼顾资源受限的嵌入式设备,又要具备细腻精确的表达能力;Lua脚本编程语言很好地填补这一空缺。实际上,Lua脚本语言太过成功,以致于国产的一些单片机提供了几乎纯Lua版本的系统SDK,例如合宙的LuatOS

可执行多任务的单线程脚本

某些情况下,对系统的一些监视、运维功能,可以使用一段简洁的Lua脚本来完成。但作为系统服务的一个,嵌入式系统开发人员并不能随意地增加或减少系统服务。因此需要有一种简单地机制,在现存的某个服务中增加一段函数,用于周期性地执行某个操作,就显得很重要了。

很幸运,Lua编程语言内置了协程,这是一种可以让多个任务同时运行的任务管理机制。本文主要介绍了笔者对Lua协程的封装模块,方便嵌入式系统开发人员随意在一个Lua脚本中增减必要的功能。因Lua有多个版本,笔者对协程的封装可以兼容各个版本(包括luajit等)。相关代码可从笔者的github仓库下载:

sh 复制代码
git clone https://github.com/jaqchen/ftask.git

多任务示例代码

该Lua模块并不是由纯Lua实现,它包含了一个用于获取系统时间的C语言模块ftime,可以通过以下命令编译:

sh 复制代码
cd ftask
make EXTRA_CFLAGS=-I/usr/include/lua5.4 # 使用`lua5.4`解析器

为了对笔者提供的简单协程的使用加以说明,笔者在仓库中提供了一个简单的示例,test.lua,运行的结果如下:

复制代码
# lua5.4 test.lua
Task 1 started with argument: Hello World
Task 2 started with type: table
Task 1 running happily! 7
Task 2 running happily! 1
Task 1 running happily! 8
Task 1 running happily! 9
Task 2 running happily! 2
Task 1 running happily! 10
Task 2 running happily! 3
Task 1 running happily! 11
INFO: restarting Lua thread at 1
Task 2 running happily! 4
Task 1 started with argument: Hello World
Task 1 running happily! 7
Task 2 running happily! 5
Warning, destory Lua thread: 2
Task 1 running happily! 8
^Clua5.4: ./ftask.lua:129: interrupted!

下面,结合该示例代码,简要地说明使用方法:

lua 复制代码
#!/usr/bin/lua

local ftask = require "ftask"
local cfmt  = string.format
local task1 = ftask.newtasks()
local function task_1(arg1)
	io.stdout:write(cfmt("Task 1 started with argument: %s\n", arg1))
	local cnt = 6
	while cnt < 11 do
		cnt = cnt + 1
		task1:mdelay(1000)
		io.stdout:write(cfmt("Task 1 running happily! %d\n", cnt))
	end
	return nil
end

local function task_2(arg2)
	io.stdout:write(cfmt("Task 2 started with type: %s\n", type(arg2)))
	local cnt = 0
	while cnt < 5 do
		cnt = cnt + 1
		task1:mdelay(1500)
		io.stdout:write(cfmt("Task 2 running happily! %d\n", cnt))
	end
	return nil
end

task1:add(task_1, "Hello World", true)
task1:add(task_2, {[1] = 1, [2] = 2}, false)
while true do
	task1:loop(60000, nil, nil)
end

其中,需要强调的是,task1:add方法,其第一个参数为某个Lua方法(或函数)入口。函数可以不返回,也可以返回。第二个参数为该方法的参数,只能有一个。第三个参数为布尔类型,指示该方法如果返回后,是否重新运行。

此外,task1:mdelay(XXX)封装了Lua协程的切换操作。它会让当前的协程在XXX毫秒之后再次运行。最后,值得注意的是task1:loop方法,它的第二个参数可以是一个Lua函数,该函数需要休眠 调用时指定的时间,例如阻塞在某个套接字的读过程中(这样就不会调用ftime.so模块同的mdelay方法),进一步利用好服务的空闲时间。

相关推荐
liulilittle1 小时前
甲骨文云中国大陆定向 QoS 原理及绕过解决方案
服务器·开发语言·网络·计算机网络·oracle·通信·qos
iCxhust1 小时前
C# 生成命令行程序 将hex格式烧录程序转换成bin烧录格式
开发语言·汇编·单片机·嵌入式硬件·c#·微机原理
Mortalbreeze1 小时前
C++11类的新特性:移动语义、default、delete、override详解
开发语言·c++
xiaoshuaishuai81 小时前
C# 封装与继承
开发语言·c#
星辰_mya2 小时前
限流、漏斗桶和令牌桶的区别
java·开发语言·面试·架构·高并发
Shadow(⊙o⊙)2 小时前
信号1.0,信号概念、signal()处理、前后台进程、闹钟设置、初识信号三张表。
linux·运维·服务器·开发语言·c++
(Charon)2 小时前
【C++ 面试高频:STL 容器 vector、map、unordered_map 总结】
开发语言·c++·面试
我是一颗柠檬2 小时前
【Java项目技术亮点】滑动窗口限流算法
java·开发语言·算法
于指尖飞舞2 小时前
java后端面试题(jvm极简)
java·开发语言·jvm