然而,使用前章方法移植到FreeRTOS上后却各种不尽人意。
来来回回搞了几个星期,最终还是实现了我的目的,先展示下效果吧!!!
压力测试11个线程。led间隔100ms闪烁,10个打印线程正常。
执行lua文件频繁时会返回如下错误:
[#err : execute fail(1) cannot open 0:/TEST.LUA: No error (errno = 0)]
原因:打开文件过快,会造成文件读取冲突,所以文件操作需要加上互斥锁。顺便一提,lua的锁lua_lock,lua_unlock也必须实现,否则乱套。用一个独立的互斥信号量即可。
单纯使用前面章节提到的函数是不能实现lua多线程的。
在gethua上找到了一份开源代码 Lua-RTOS-ESP32,很值得学习。我从中摘取了线程创建及调用部分代码。
源码参考其中的thread.c文件。
我的项目只需要简单的线程创建运行即可,考虑到线程参数的传递,我用了一个table作为传递介质。方便灵活的传递我们需要的参数。
文件:lua_task.c
#define STACK_DEFAULT 512 //堆栈默认大小
#define PRIORITY_DEFAULT 5 //线程优先级
#define TASKNAME_DEFAULT "task" //线程名
static void _task(void *arg)
{
lthread_t *thread = (struct lthread *)arg;
int inParamLen = lua_gettop(thread->L) - 1;//除去栈底函数的参数个数,其实创建时已限定总栈个数为2.
int status = lua_pcall(thread->L, inParamLen, 0, 0);
if (status != LUA_OK)
{
const char *msg = lua_tostring(thread->L, 1);
printf(" thread pacll err:<%d> %s\r\n", status, msg);
}
free(thread);
vTaskDelete(NULL);
}
static int TaskRun(lua_State *L)
{
if (lua_isfunction(L, 1) == 0)
{
printf("err: TaskRun param don function\r\n");
return 0;
}
struct lthread *thread;
int stack = STACK_DEFAULT;
int priority = PRIORITY_DEFAULT;
const char *name = TASKNAME_DEFAULT;
if (lua_istable(L, 2)) //第一个参数是不是table
{
lua_pushstring(L, "stack");
lua_gettable(L, 2);
stack = luaL_optinteger(L, -1, STACK_DEFAULT);
lua_pushstring(L, "priority");
lua_gettable(L, 2);
priority = luaL_optinteger(L, -1, PRIORITY_DEFAULT);
lua_pushstring(L, "name");
lua_gettable(L, 2);
name = luaL_optstring(L, -1, TASKNAME_DEFAULT);
}
//printf(" %d %d %s\r\n",stack,priority,name);
//return 0;
// Get stack size, priotity and cpu affinity
if (stack < 512)
{
printf("err: task stack[%d] is small\r\n", stack);
return 0;
}
// Allocate space for lthread info
thread = (struct lthread *)malloc(sizeof(struct lthread));
if (!thread)
{
printf("err: thread malloc fail\r\n");
return 0;
}
// Check for argument is a function, and store it's reference
//luaL_checktype(L, 1, LUA_TFUNCTION);
thread->function_ref = luaL_ref(L, LUA_REGISTRYINDEX);
// Create a new state, move function to it and store thread reference
thread->PL = L;
thread->L = lua_newthread(L);
thread->thread_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_rawgeti(L, LUA_REGISTRYINDEX, thread->function_ref);
int top = lua_gettop(L);
if(top>2) top = 2;
// Ensure that we have only the thread function in the lua stack prior to
// move it to the lua thread stack
lua_settop(L, top);//移除多余的传入参数
lua_xmove(L, thread->L, top);//拷贝栈到子线程栈 thread->L
//创建线程
TaskHandle_t taskHandle;
xTaskCreate(_task, name, stack, thread, priority, &taskHandle);
lua_pushinteger(L, (int)taskHandle);//预留后续可以管理线程
return 1;
}
const luaL_Reg ledLib[] =
{
{"run", TaskRun},
{"led_on", led_on},
{"led_off", led_off},
{"tab", table_test},
{NULL, NULL}};
文件:0:/test.lua
task.run(
function()
while true do
os.sleep(100)
task.led_on()
os.sleep(100)
task.led_off()
print("led_task")
end
end
)
function task_fun(data)
local a = 0
while true do
a = a + 1
os.sleep(100)
print("task" .. data.param .. " -run > " .. a)
end
end
for i = 1, 10 do
task.run(task_fun, {param = i})
end
task9 -run > 21086
task4 -run > 21086
task8 -run > 21086
task6 -run > 21086
task10 -run > 21086
led_task
task2 -run > 21087
task1 -run > 21087
task5 -run > 21087
task7 -run > 21087
task3 -run > 21087
task9 -run > 21087
task4 -run > 21087
task8 -run > 21087
task6 -run > 21087
task10 -run > 21087
task2 -run > 21088
。。。。。。
至此,移植工作算是有突破性的进展,后续会多方面测试系统的稳定型。应该会有一些问题,希望大家能提示完善一下。