如何放弃LuaJ协程LuaThread?

4
我正在尝试一种游戏机制,玩家可以在游戏内计算机上运行脚本。在游戏过程中,脚本执行将受到资源限制,每个时钟周期有一定数量的指令。
以下概念验证演示了基本级别的沙盒和任意用户代码的节流。它成功地运行了约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 - 处理或中断无限循环和线程

编辑:我在LuaJ SourceForge发布了一个漏洞报告。它讨论了潜在的问题(线程未像Lua规范中那样被垃圾回收)并提出了一些解决方法。

1个回答

3
这似乎是LuaJ的限制。我在Sourceforge上提交了一个请求,就像您所做的一样。 LuaThread 类不存储对其创建的Java线程的引用,因此您无法在不修改LuaJ核心以公开它们的情况下 interrupt()这些线程:

new Thread(this,“Coroutine-”+(++ coroutine_count))。开始();

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


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

“指示检测到不再引用的lua线程的错误子类。抛出此错误的Java线程应该对应于正在用作协程的LuaThread,因为没有更多与其关联的LuaThread的引用。而不是永远锁定资源,抛出此错误,并且应该完全通过线程的Thread.run()方法。”

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


在Lua / J中,空循环和非空循环之间也似乎存在差异。如果我没记错,空循环( while true do end )不遵守所有协程钩子/ tick规则。 *因为空循环中没有任何操作,因此某些挂钩没有机会发生(我需要再次测试,请纠正我!)。

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


当文档说“与其关联的LuaThread没有更多引用”时,很难知道它的含义。如果它指的是在Lua中调用coroutine.create()时生成的LuaThread,则我在Java代码中从未持有对其的引用。因此,它仍然存在是由于LuaJ底层的某些怪癖。关于空while循环,它们仍会增加指令计数器并触发调试钩子。 - David Lewis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接