我如何放弃 LuaJ 协程 LuaThread?

我正在尝试一种游戏机制,玩家可以在游戏内计算机上运行脚本。在游戏过程中,脚本的执行将受到资源的限制,每个时钟周期只能执行一些指令。

下面的概念验证演示了任意用户代码的基本沙盒和限制。它成功地运行了约250条不良设计的“用户输入”指令,然后丢弃了协程。不幸的是,Java进程永远不会终止。一些调查表明,由LuaJ为协程创建的“LuaThread”将永远挂起。

SandboxTest.java:

public static void main(String [] args){
    Globals globals = JsePlatform.debugGlobals();

    LuaValue chunk = globals.loadfile(“ res / test.lua”);

    chunk.call();
}

res / test.lua:

function sandbox(fn)
    - 读取脚本并设置环境
    f = loadfile(fn,“t”)
    debug.setupvalue(f,1,{print = print})

    - 创建协程并使其每50个指令yield一次
    local co = coroutine.create(f)
    debug.sethook(co,coroutine.yield,“”,50)

    - 演示分步执行,5“tick”
    for i = 1,5 do
        print(“tick”)
        coroutine.resume(co)
    end
end

sandbox(“ res / badfile.lua”)

res / badfile.lua:

while 1 do
    print(“”,“badfile”)
end

文档建议认为不可恢复的协程将被垃圾回收,并将抛出一个OrphanedThread异常,从而发出信号LuaThread结束,但是这从未发生过。我的问题分为两个部分:

  • 我是否做了一些根本性的错误以导致这种行为?
  • 如果没有,我应该如何处理这种情况?从源代码中可以看出,如果我可以在Java中获取对LuaThread的引用,我可以通过发出“中断()interrupt()”来强制放弃它。这是一个好主意吗?

参考:Lua / Java / LuaJ - Handling or Interrupting Infinite Loops and Threads

编辑:我已经在LuaJ SourceForge上发布了一个错误报告。它讨论了潜在问题(线程未像Lua规范中那样垃圾回收)并建议了一些解决方法。

点赞
用户1127098
用户1127098

看起来这是LuaJ的局限性。我今年早些时候在Sourceforge上提出了一个问题,就像你也做的那样。LuaThread类不存储对其创建的Java线程的引用,因此您无法在不修改LuaJ核心以暴露它们的情况下interrupt()这些线程:

new Thread(this, "Coroutine-"+(++coroutine_count)).start();

在没有添加适当的清理代码的情况下,中断这些线程可能会很危险。


你提供的OrphanedThread文档还告诉我们,作用域是定义条件:

"表示检测到不再引用的lua线程的错误子类。抛出此错误的Java线程应对应于作为协同程序使用的LuaThread,它不可能再次启动,因为没有更多与其关联的LuaThread的引用。而不是永远锁定资源,抛出该错误,应当一路落入线程的Thread.run()方法。"

您的代码示例并不会导致所有LuaThread引用消失,因此您不应该期望抛出异常。 CoroutineLib文档指出:“挂起但从未恢复执行的协同程序可能不会被垃圾收集器回收”,因此如果我没有弄错的话,从您在SourceForge上列出的代码中实际上应该_预期_发生OutOfMemoryErrorLuaThread:52还指定:“应用程序不应捕获OrphanedThread,因为它可能会破坏luaj的线程安全性。”这是另一个障碍。


Lua/J中空和非空的while循环之间也似乎存在差异。如果我没记错的话,空循环(while true do end)不遵循所有协程钩子/刻度规则。 *因为空循环中没有任何动作,所以某些挂钩无法发生(我需要再测试一下,否则请纠正我!)。

Minecraft的ComputerCraft模组中使用了我们正在寻找的功能的LuaJ分支版本,尽管它仅为该模组设计,不是开源的。

2014-07-07 19:17:53