暂停 lua 来自外部函数的协程以在调度程序中使用

Pause lua coroutine from outside function for use in a scheduler

这已经在之前讨论过,从外部可以完成的所有事情似乎就是杀死协程。这对于调度程序来说当然是不实用的。有没有办法从外部暂停协程或者可能有解决方法?

从 C API,您可以 set a hook 将在 $n 行/指令后产生。 (这通过 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 change/remove 设置钩子,反之亦然——这会抛出错误或默默地造成混乱。但你可以扩展 setyieldhook 来检测& clear "normal" Lua hooks,and/or wrap debug.sethook 检查并清除 yield hook。)

其他注意事项:

  • 如果协程yields,这不会重置挂钩计时器。
  • 协程将退出而不返回任何东西,所以你可能想要 包装 coroutine.yield and/or coroutine.resume 这样你就可以区分了 "normal" yields 从超时开始 yields.
  • C 函数不计算处理的指令数,因此 不会触发钩子(例如 long-运行 非贪婪字符串匹配通过 string.*),因此这不提供硬时序保证。