【问题标题】:Lua co-routinesLua 协程
【发布时间】:2011-11-04 14:31:44
【问题描述】:

我正在尝试了解如何使用协同程序来“暂停”脚本并等到某些处理完成后再恢复。

也许我以错误的方式看待协同例程。但我的尝试的结构类似于answer 中给出的示例。

loop.lua 中的循环永远不会达到第二次迭代,因此永远不会达到退出 C 代码中正在运行的循环所需的 i == 4 条件。如果我没有在loop.lua 中让步,那么此代码将按预期执行。

ma​​in.cpp

#include <lua/lua.hpp>

bool running = true;

int lua_finish(lua_State *) {
    running = false;
    printf("lua_finish called\n");
    return 0;
}
int lua_sleep(lua_State *L) {
    printf("lua_sleep called\n");
    return lua_yield(L,0);
}

int main() {
    lua_State* L = lua_open();
    luaL_openlibs(L);

    lua_register(L, "sleep", lua_sleep);
    lua_register(L, "finish", lua_finish);

    luaL_dofile(L, "scripts/init.lua");

    lua_State* cL = lua_newthread(L);
    luaL_dofile(cL, "scripts/loop.lua");

    while (running) {
        int status;
        status = lua_resume(cL,0);
        if (status == LUA_YIELD) {
            printf("loop yielding\n");
        } else {
            running=false; // you can't try to resume if it didn't yield
            // catch any errors below
            if (status == LUA_ERRRUN && lua_isstring(cL, -1)) {
                printf("isstring: %s\n", lua_tostring(cL, -1));
                lua_pop(cL, -1);
            }
        }
    }

    luaL_dofile(L, "scripts/end.lua");
    lua_close(L);
    return 0;
}

loop.lua

print("loop.lua")

local i = 0
while true do
    print("lua_loop iteration")
    sleep()

    i = i + 1
    if i == 4 then
        break
    end
end

finish()

编辑:添加了赏金,希望能在如何完成此任务方面获得一些帮助。

【问题讨论】:

    标签: c++ scripting lua coroutine


    【解决方案1】:

    lua_resume 的返回代码 2 是 LUA_ERRRUN。检查 Lua 堆栈顶部的字符串以找到错误消息。

    类似的模式对我有用,尽管我确实使用了coroutine.yield 而不是lua_yield,而且我使用的是 C 而不是 C++。我不明白为什么您的解决方案不起作用

    在您的简历电话中,不清楚您是否过度简化了示例,但我会在您的 while 循环中进行以下更改:

    int status;
    status=lua_resume(cL,0);
    if (status == LUA_YIELD) {
      printf("loop yielding\n");
    }
    else {
      running=false; // you can't try to resume if it didn't yield
      // catch any errors below
      if (status == LUA_ERRRUN && lua_isstring(cL, -1)) {
        printf("isstring: %s\n", lua_tostring(cL, -1));
        lua_pop(cL, -1);
      }
    }
    

    编辑 2:

    对于调试,请在运行简历之前添加以下内容。你有一个字符串被推到堆栈的某个地方:

    int status;
    // add this debugging code
    if (lua_isstring(cL, -1)) {
      printf("string on stack: %s\n", lua_tostring(cL, -1));
      exit(1);
    }
    status = lua_resume(cL,0);
    

    编辑 3:

    哦,天哪,我不敢相信我还没有看到这一点,当你要让步时,你不想运行luaL_dofile,因为据我所知,你不能直接生成 pcall ,这就是dofile中发生的事情(5.2会通过,但我认为你仍然需要lua_resume)。切换到这个:

    luaL_loadfile(cL, "scripts/loop.lua");
    

    【讨论】:

    • 错误码2仅在resume code连续运行时出现(不止一个,没有另一个yield)。我得到的任何其他错误是:“尝试调用字符串值”。流行代码:if (lua_isstring(cL, -1)) { printf("isstring: %s\n", lua_tostring(cL, -1)); lua_pop(cL, -1); }
    • “尝试调用字符串”表示堆栈上除了您的例程之外还有其他内容,可能是错误消息。当 resume 以 return 0 结束时,例程就完成了,你不能再继续它了,它不再在堆栈上。如果您上次获得了 yield 或将新例程压入堆栈,您只能再次恢复。
    • 如果不是通过上面的代码,我怎样才能得到错误信息?
    • AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH。 luaL_loadfile(cL, "scripts/loop.lua");现在一切正常... crys。谢谢!
    • @Daniel,不客气,仍然不敢相信我直到现在才看到。
    【解决方案2】:

    上次我弄乱了 Lua 协程我以这样的代码结束

    const char *program =
    "function hello()\n"
    "  io.write(\"Hello world 1!\")\n"
    "  io.write(\"Hello world 2!\")\n"
    "  io.write(\"Hello world 3!\")\n"
    "end\n"
    "function hate()\n"
    "  io.write(\"Hate world 1!\")\n"
    "  io.write(\"Hate world 2!\")\n"
    "  io.write(\"Hate world 3!\")\n"
    "end\n";
    
    const char raw_program[] = 
    "function hello()\n"
    "  io.write(\"Hello World!\")\n"
    "end\n"
    "\n"
    "cos = {}\n"
    "\n"
    "for i = 0, 1000, 1 do\n"
    "  cos[i] = coroutine.create(hello)\n"
    "end\n"
    "\n"
    "for i = 0, 1000, 1 do\n"
    "  coroutine.resume(cos[i])\n"
    "end";
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        lua_State *L = lua_open();
        lua_State *Lt[1000];
        global_State *g = G(L);
    
        printf("Lua memory usage after open: %d\n", g->totalbytes);
    
        luaL_openlibs(L);
    
        printf("Lua memory usage after openlibs: %d\n", g->totalbytes);
    
        lua_checkstack(L, 2048);
    
        printf("Lua memory usage after checkstack: %d\n", g->totalbytes);
    
        //lua_load(L, my_lua_Reader, (void *)program, "code");
        luaL_loadbuffer(L, program, strlen(program), "line");
    
        printf("Lua memory usage after loadbuffer: %d\n", g->totalbytes);
    
        int error = lua_pcall(L, 0, 0, 0);
        if (error) {
            fprintf(stderr, "%s", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
    
        printf("Lua memory usage after pcall: %d\n", g->totalbytes);
    
        for (int i = 0; i < 1000; i++) {
            Lt[i] = lua_newthread(L);
            lua_getglobal(Lt[i], i % 2 ? "hello" : "hate");
        }
    
        printf("Lua memory usage after creating 1000 threads: %d\n", g->totalbytes);
    
        for (int i = 0; i < 1000; i++) {
            lua_resume(Lt[i], 0);
        }
    
        printf("Lua memory usage after running 1000 threads: %d\n", g->totalbytes);
    
        lua_close(L);
    
        return 0;
    }
    

    您似乎无法将文件加载为协程?而是改用函数,而且应该选择到栈顶。

    lua_getglobal(Lt[i], i % 2 ? "hello" : "hate");
    

    【讨论】:

    • 无需在 Lua 脚本中创建协程,lua_newthread 调用在 C/C++ 中完成。我自己使用它没有任何问题。
    • 其实我没有加载 raw_program。我应该从我的帖子中删除它。但是,是的,我明白了。问题在于恢复协程。不启动它们。应该仔细阅读原帖
    • 刚刚看到您在示例中使用了lua_newthread。但是,是的,OP 在产生协程后有问题。
    猜你喜欢
    • 2015-01-23
    • 2013-09-28
    • 1970-01-01
    • 2016-03-22
    • 2013-10-31
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    相关资源
    最近更新 更多