You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:24:01