如何放弃LuaJ协程LuaThread? [英] How can I abandon a LuaJ coroutine LuaThread?

查看:208
本文介绍了如何放弃LuaJ协程LuaThread?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试一种游戏机制,玩家可以在游戏机上运行脚本.脚本执行将在游戏级别上限制为每个刻度一定数量的指令.

I am experimenting with a game mechanic in which players can run scripts on in-game computers. Script execution will be resource limited at a gameplay level to some amount of instructions per tick.

以下概念验证演示了任意用户代码的沙盒处理和限制操作的基本级别.它成功地执行了约250条操作不当的用户输入"指令,然后丢弃了协程.不幸的是,Java进程永远不会终止.一项小小的调查显示,LuaJ为协程创建的LuaThread永远存在.

The following proof-of-concept demonstrates a basic level of sandboxing and throttling of arbitrary user code. It successfully runs ~250 instructions of poorly crafted 'user input' and then discards the coroutine. Unfortunately, the Java process never terminates. A little investigation in shows that the LuaThread created by LuaJ for the coroutine is hanging around forever.

SandboxTest.java:

SandboxTest.java:

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

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

    chunk.call();
}

res/test.lua:

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:

res/badfile.lua:

while 1 do
    print("", "badfile")
end

文档建议将被视为不可恢复的协程进行垃圾收集,并且 OrphanedThread 异常将被抛出,表示 LuaThread 结束-但这从未发生.我的问题分为两个部分:

The docs suggest that a coroutine that is considered unresumable will be garbage collected and an OrphanedThread exception will be thrown, signalling the LuaThread to end - but this is never happening. My question is in two parts:

  • 我是从根本上做错了什么导致这种行为的吗?
  • 如果没有,我应该如何处理这种情况?从源头看来,如果我可以在Java中获得对LuaThread的引用,则可以通过发出interrupt()来强行放弃它.这是个好主意吗?
  • Am I doing something fundamentally wrong to cause this behaviour?
  • If not, how should I handle this situation? From the source it appears that if I can get a reference to the LuaThread in Java I may be able to forcibly abandon it by issuing an interrupt(). Is this a good idea?

参考: Lua/Java/LuaJ-处理或中断无限循环和线程

我已经在LuaJ SourceForge上发布了错误报告.它讨论了潜在的问题(不像Lua规范中那样垃圾被垃圾收集),并提出了解决该问题的一些方法.

I have posted a bug report over at the LuaJ SourceForge. It discusses the underlying issue (threads not being garbage collected as in the Lua spec) and suggests some ways to work around it.

推荐答案

这似乎是LuaJ的局限性.我看到您也已经完成了,所以我今年初在Sourceforge上提交了一张票. LuaThread类不会存储对它创建的Java线程的引用,因此,如果不修改LuaJ核心以暴露它们,就不能interrupt()这些线程:

It seems to be a limitation of LuaJ. I submitted a ticket earlier this year on Sourceforge as I see you've also done. The LuaThread class doesn't store references to the Java threads it creates, so you can't interrupt() those threads without modifying the LuaJ core to expose them:

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

在不向LuaJ中添加适当的清除代码的情况下中断那些线程可能很危险.

It may be dangerous to interrupt those threads without adding appropriate cleanup code to LuaJ.

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

Documentation that you provided for OrphanedThread also tells us that scope is the defining condition:

已检测到指示不再引用的lua线程的错误子包.抛出该Java线程的Java线程应对应于被用作协程的LuaThread,由于不再有与其关联的LuaThread引用.并非永远锁定资源,而是抛出该错误,并且应该一直贯穿到线程的Thread.run()方法中."

"Error sublcass that indicates a lua thread that is no longer referenced has been detected. The java thread in which this is thrown should correspond to a LuaThread being used as a coroutine that could not possibly be resumed again because there are no more references to the LuaThread with which it is associated. Rather than locking up resources forever, this error is thrown, and should fall through all the way to the thread's Thread.run() method."

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

Your code example doesn't cause all LuaThread references to disappear, so you shouldn't expect an exception to be thrown. CoroutineLib documentation indicates: Coroutines that are yielded but never resumed to complete their execution may not be collected by the garbage collector, so an OutOfMemoryError should actually be expected from the code you listed on SourceForge, if I'm not mistaken. LuaThread:52 also specifies: Applications should not catch OrphanedThread, because it can break the thread safety of luaj., which is yet another obstacle.

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

There also seem to be differences between empty and non-empty while loops in Lua/J. IIRC, empty loops (while true do end) don't obey all coroutine hook/tick rules. *Because no actions occur in an empty loop, there's no opportunity for certain hooks to occur (I need to test this again so please correct me otherwise!).

具有Minecraft需求的功能的LuaJ分支版本在Minecraft的ComputerCraft Mod中使用,尽管它仅是为Mod设计的,并且不是开源的.

A forked version of LuaJ with the functionality we're looking for is used in the ComputerCraft mod for Minecraft, though it's designed only for the mod and isn't open source.

这篇关于如何放弃LuaJ协程LuaThread?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆