【问题标题】:Pause lua coroutine from outside function for use in a scheduler从外部函数暂停 lua 协程以在调度程序中使用
【发布时间】:2017-07-02 14:07:23
【问题描述】:

这在之前已经讨论过了,所有可以从外部做的似乎就是杀死协程。这对于调度程序当然是不切实际的。有没有办法从外部暂停协程或解决方法?

【问题讨论】:

    标签: lua coroutine


    【解决方案1】:

    从 C API,您可以在 $n 行/指令之后产生 set a hook。 (这通过debug.sethook 是不可能的,因为它添加了一个中间层来阻止它工作。)

    你可以把它封装成一个可以暴露给 Lua 的函数,所以除了添加那个函数之外,你还可以从 Lua 中完成。示例:

    static int setyieldhook( lua_State * L ) {
       lua_State * coro;
       int steps;
       luaL_checktype( L, 1, LUA_TTHREAD );
       coro = lua_tothread( L, 1 );
       steps = luaL_optinteger( L, 2, 0 );
       if (steps <= 0) {
          lua_sethook( coro, NULL, 0, 0 );
       } else {
          lua_sethook( coro, yieldhook, LUA_MASKCOUNT, steps );
       }
       return 0;
    }
    

    然后将其作为函数推送到 Lua 并为其命名,例如debug.setyieldhook.

    这个将被用作debug.setyieldhook( coro, timeout ) 并且每当协程运行时,它将在timeout Lua 指令之后产生。要清除,debug.setyieldhook( coro, 0 )。 (注意:您不能更改/删除通过setyieldhookdebug.sethook 设置的钩子,反之亦然——这将引发错误或默默地造成混乱。但您可以扩展setyieldhook 以检测和清除“正常” Lua 钩子,和/或包装 debug.sethook 以检查并清除 yield 钩子。)

    其他需要注意的事项:

    • 如果协程yields,这不会重置挂钩计时器。
    • 协程将在不返回任何内容的情况下屈服,因此您可能想要 包装coroutine.yield 和/或coroutine.resume 这样你就可以区分 “正常”yields 来自超时 yields。
    • C 函数不计算已处理的指令数,因此 不会触发钩子(例如,长时间运行的非贪婪字符串匹配通过 string.*),所以这不提供硬性时序保证。

    【讨论】:

    • 这是一个我可以使用的可行选项,但快速的问题是,我可以使用标准 lua 中的任何实现吗?也许以某些代码行间隔将 coroutine.yield() 插入到执行函数中?为我的环境设置 C 对我来说有点不便,但如果不存在,我将使用上述选项
    • @Varscott11 好吧,您可以包装库函数来增加内部(共享)计数器,偶尔也会增加yield。 (所以你实际上是在模拟一个操作系统,比方说,所有ioos、...函数can如果时间到了。)或者也许(没试过这个一)设置一个具有任意超时条件的普通钩子,它只用带有__index/__newindex的虚拟表替换全局环境或一些经常访问的东西。当元方法触发时,它会将其更改回正常事物,让步,然后(在恢复后)对正常事物重新执行劫持操作。
    • @Varscott11 (但这都是 hacky,而不是你想要依赖的东西来认真使用。这对于快速测试等很好,但是有很多奇怪的交互和难以测试的潜力- 损坏。所以如果你想在库中使用它/提供给其他人/...)
    猜你喜欢
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-03
    • 2017-08-23
    • 2019-12-11
    • 1970-01-01
    相关资源
    最近更新 更多