【问题标题】:How can I abandon a LuaJ coroutine LuaThread?如何放弃 LuaJ 协程 LuaThread?
【发布时间】:2014-08-26 10:35:31
【问题描述】:

我正在试验一种游戏机制,让玩家可以在游戏内的计算机上运行脚本。脚本执行将在游戏级别受到资源限制,每次滴答需要一定数量的指令。

以下概念验证演示了沙盒和任意用户代码限制的基本级别。它成功运行了约 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 规范中那样被垃圾收集)并提出了一些解决方法。

【问题讨论】:

    标签: java multithreading lua coroutine luaj


    【解决方案1】:

    这似乎是 LuaJ 的一个限制。我今年早些时候在 Sourceforge 上提交了一张票,我看到你也这样做了。 LuaThread 类不存储对其创建的 Java 线程的引用,因此您不能在不修改 LuaJ 核心以公开它们的情况下 interrupt() 那些线程:

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

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


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

    "检测到错误子类,指示不再引用的 lua 线程。抛出此错误的 java 线程应对应于被用作不可能再次恢复的协程的 LuaThread,因为 没有更多对与其关联的 LuaThread 的引用。 与其永远锁定资源,不如抛出此错误,并且应该一直传递到线程的 Thread.run() 方法。"

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


    Lua/J 中的空和非空 while 循环似乎也存在差异。 IIRC,空循环 (while true do end) 不遵守所有协程挂钩/刻度规则。 *由于空循环中没有任何动作发生,因此某些钩子没有机会发生(我需要再次测试,否则请纠正我!)。

    具有我们正在寻找的功能的 LuaJ 的分叉版本已用于 Minecraft 的 ComputerCraft 模组,但它仅为模组而设计,并非开源。

    【讨论】:

    • 当文档说“没有更多对其关联的 LuaThread 的引用”时,很难知道文档的含义。如果这意味着当我在 Lua 中调用 coroutine.create() 时在库中生成 LuaThread,那么我的 Java 代码中永远不会引用它。因此,由于 LuaJ 引擎盖下的一些怪癖,它仍然活着。关于空的while循环,它们仍然会增加指令计数器并触发调试钩子。
    猜你喜欢
    • 2011-04-08
    • 2012-08-21
    • 1970-01-01
    • 2011-04-01
    • 2015-08-13
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2010-10-04
    相关资源
    最近更新 更多