我正在尝试一种游戏机制,在该机制中,玩家可以在游戏机上运行脚本。脚本执行在游戏级别上将受到资源限制,每次滴答声会限制一定数量的指令。

以下概念验证演示了任意用户代码的沙盒处理和限制操作的基本级别。它成功地执行了约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)
    -- read script and set the environment
    f = loadfile(fn, "t")
    debug.setupvalue(f, 1, {print = print})

    -- create a coroutine and have it yield every 50 instructions
    local co = coroutine.create(f)
    debug.sethook(co, coroutine.yield, "", 50)

    -- demonstrate stepped execution, 5 'ticks'
    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上发布了bug report。它讨论了潜在的问题(不像Lua规范中那样垃圾被垃圾收集),并提出了解决该问题的一些方法。

    最佳答案

    这似乎是LuaJ的局限性。我看到您也已经完成了,所以我今年初在Sourceforge上提交了一张票。 LuaThread类不会存储对它创建的Java线程的引用,因此,如果不修改LuaJ核心以暴露它们,就无法interrupt()这些线程:
    new Thread(this, "Coroutine-"+(++coroutine_count)).start();
    在不向LuaJ中添加适当的清除代码的情况下中断那些线程可能很危险。

    您为 OrphanedThread 提供的文档还告诉我们范围是定义条件:

    “已检测到指示不再引用lua线程的错误sublcass。在其中抛出Java线程的Java线程应对应于被用作协程的LuaThread,由于不再有对它的引用,因此无法再次恢复而不是永远锁定资源,而是引发该错误,并且应该一直贯穿到线程的Thread.run()方法中。”

    您的代码示例不会导致所有LuaThread引用都消失,因此,您不应期望会引发异常。 CoroutineLib 文档指示:Coroutines that are yielded but never resumed to complete their execution may not be collected by the garbage collector,因此,如果我没有记错的话,实际上应该从the code you listed on SourceForge中获得一个OutOfMemoryErrorLuaThread:52还指定:Applications should not catch OrphanedThread, because it can break the thread safety of luaj.,这是另一个障碍。

    Lua/J中的空和非空while循环之间似乎也存在差异。 IIRC,空循环(while true do end)不遵守所有协程钩子(Hook)/勾号规则。 *由于在空循环中没有任何 Action ,因此没有机会发生某些异常现象(我需要再次测试,否则请更正我!)。

    LuaJ的 fork 版本具有我们正在寻找的功能,用于Minecraft的ComputerCraft mod中,尽管它仅针对该mod设计,并且不是开源的。

    09-05 20:29