如何通过Lua C API创建Lua协程并将其暴露给Lua层调用
C开发Lua扩展库实现导出可直接调用的协程方案
核心原理
coroutine.resume的首个入参要求是Lua协程对象,要实现你给出的调用写法,只需要在C模块初始化时提前创建绑定了业务逻辑的协程对象,挂载到模块导出表即可。
依赖的核心Lua C API
lua_newthread(L):创建新的Lua协程,将协程对象压入当前栈,同时返回该协程对应的独立lua_State指针lua_pushcfunction(co, func)/lua_pushcclosure(co, func, n):将你实现的C业务逻辑函数压入协程的栈,作为协程启动后的执行入口lua_yield(co, n):挂起当前协程,参数n为返回给coroutine.resume调用侧的返回值数量,协程下次被resume时会从yield位置继续执行
完整实现示例
C侧代码
#include <lua.h> #include <lauxlib.h> #include <lualib.h> // 协程业务逻辑入口,返回值为返回给Lua侧的参数个数 static int my_co_body(lua_State *co) { // 接收第一次resume传入的参数 int input = luaL_checkinteger(co, 1); // 第一阶段业务逻辑处理 lua_pushinteger(co, input * 2); lua_pushstring(co, "first stage done"); // 挂起协程,返回2个值给resume调用方 return lua_yield(co, 2); // 第二次resume后从这里继续执行,接收第二次resume传的参数 int resume_input = luaL_checkinteger(co, 1); // 第二阶段业务逻辑处理 lua_pushinteger(co, resume_input + 100); // 协程执行结束,返回1个最终值 return 1; } // 模块入口函数,要求命名符合luaopen_模块名的格式 int luaopen_mymodule(lua_State *L) { // 初始化导出模块表 lua_newtable(L); // 创建协程对象 lua_State *co = lua_newthread(L); // 绑定协程的业务逻辑入口 lua_pushcfunction(co, my_co_body); // 将协程对象挂载到模块表的coroutine_function字段 lua_setfield(L, -3, "coroutine_function"); // 如果需要支持创建多个独立协程实例,可额外导出创建函数 static const luaL_Reg module_funcs[] = { {"create_coroutine", [](lua_State *L) -> int { lua_State *new_co = lua_newthread(L); lua_pushcfunction(new_co, my_co_body); return 1; } }, {NULL, NULL} }; luaL_setfuncs(L, module_funcs, 0); // 返回模块表给Lua侧 return 1; }
Lua侧调用测试
和你要求的写法完全兼容:
local module = require("mymodule") -- 直接调用模块导出的协程 local ok, ret1, ret2 = coroutine.resume(module.coroutine_function, 50) print(ok, ret1, ret2) -- 输出:true 100 first stage done -- 第二次恢复协程执行 local ok, final_ret = coroutine.resume(module.coroutine_function, 20) print(ok, final_ret) -- 输出:true 120 -- 如果要使用独立协程实例,调用导出的创建方法 local co = module.create_coroutine() coroutine.resume(co, 100)
注意事项
- 单个提前创建的协程是全局单例,多地方同时调用会出现状态冲突,要多实例的场景请使用导出的
create_coroutine方法新建独立协程 lua_yield只能在当前正在执行的协程上下文中调用,不能从主线程或者其他协程的栈调用- C侧不要执行长时间阻塞的逻辑,要拆分成多段执行,每段结束后主动yield交回控制权,避免卡住Lua调度
内容的提问来源于stack exchange,提问作者Vipul Cariappa
相关产品推荐
相关产品推荐

