Lua 协程

我试图了解如何使用协同程序来“暂停”一个脚本,等待一些处理完成后再继续执行。

也许我没有正确理解协同程序的用法。但是我的尝试类似于此答案中给出的示例。

loop.lua中的循环从未达到第二次迭代,因此从未达到C代码中需要退出运行循环的i == 4条件。如果我在loop.lua中不yield,则此代码将按预期执行。

main.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()

编辑:添加了一份悬赏,希望能够得到一些关于如何实现这一目标的帮助。

原文链接 https://stackoverflow.com/questions/7206411

点赞
stackoverflow用户596285
stackoverflow用户596285

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

我使用了类似的模式,但我使用了coroutine.yield而不是lua_yield,而且我使用的是C而不是C ++。我不明白你的解决方案为什么不起作用。

在您的resume调用中,如果您过于简化示例,那么在while循环中进行以下更改:

int status;
status=lua_resume(cL,0);
if (status == LUA_YIELD) {
  printf("loop yielding\n");
}
else {
  running=false; // 无法恢复,如果没有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:

为了调试,请在运行resume之前添加以下内容。您有一个字符串在某个地方被推到堆栈上:

int status;
// 添加此调试代码
if (lua_isstring(cL, -1)) {
  printf("string on stack: %s\n", lua_tostring(cL, -1));
  exit(1);
}
status = lua_resume(cL,0);

编辑3:

天啊,我不敢相信我没有早点看到这个,当您要进行yield时,您不应该运行luaL_dofile,因为我所知道的最好的办法是无法直接yield pcall,这就是在dofile中发生的(5.2将通过,但我认为仍然需要lua_resume)。转换为以下内容:

luaL_loadfile(cL, "scripts/loop.lua");
2011-08-26 20:00:59
stackoverflow用户264358
stackoverflow用户264358

上次我在用 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");
2011-08-30 15:57:21