我正在使用NLua在我的应用程序中运行Lua脚本。我需要实现在任何时候终止运行在单独线程中的脚本的能力,例如用户按下“停止”按钮,脚本必须立即终止。我读过关于SetDebugHook的文章,并试图关闭Lua并调用状态上的错误,但我总是得到AccessViolationException。
我试过了
Lua env = new Lua(); // created in main thread
env.DoString(); // called in second thread
// Called in main thread
public void Stop()
{
env.Close(); // Didn't work. AccessViolationException
env.State.Close(); // Didn't work. AccessViolationException
env.State.Error("err"); // Didn't work. AccessViolationException
}尝试将线程与锁同步
lock (locker)
{
if (env.IsExecuting)
env.Close();
}同样的问题。AccessViolationException
谢谢。
发布于 2020-06-19 22:32:11
该方法工作得相当好,在执行每一行lua代码之前,使用lua_sethook检查要中止的信号:
public partial class NluaThreading : Form
{
private Lua state;
private bool abort;
public NluaThreading()
{
InitializeComponent();
}
private void Start_Click(object sender, EventArgs e)
{
state = new Lua();
state.SetDebugHook(KeraLua.LuaHookMask.Line, 0);
state.DebugHook += State_DebugHook;
abort = true; //force abort after first debughook event
new Thread(DoLua).Start();
}
private void State_DebugHook(object sender, NLua.Event.DebugHookEventArgs e)
{
if (abort)
{
Lua l = (Lua)sender;
l.State.Error("Execution manually aborted");
}
}
private void DoLua()
{
try
{
state.DoString("while(true) do end");
}
catch (Exception e)
{
MessageBox.Show(e.Message, "DoLua", MessageBoxButtons.OK);
}
}
}当然,这是以每一行增加一些开销为代价的,以减少您可以更改其他值之一的挂钩。
另一个选项是使用lua线程将监视的令牌,然后根据需要中止,此方法确实需要在lua脚本中进行一些处理:
public partial class NluaThreading : Form
{
internal class Tokens
{
public bool abort = false;
}
private Lua state;
private Tokens tokens;
public NluaThreading()
{
InitializeComponent();
state = new Lua();
tokens = new Tokens();
state["tokens"] = tokens; //now the tokens are visible inside the lua
//environment and will reflect changes we make
//from the main thread
}
private void Start_Click(object sender, EventArgs e)
{
if (!state.IsExecuting)
{
tokens.abort = false;
new Thread(DoLua).Start();
}
}
private void Stop_Click(object sender, EventArgs e) => tokens.abort = true;
private void DoLua() => state.DoString("repeat print(tokens.abort) until(tokens.abort); print(tokens.abort)");
}现在,您的lua执行通常会更加复杂,包含许多嵌套循环,在这些情况下,您可以在lua中实现一个函数来检查令牌,并在令牌为真时抛出一个错误:
function checkTokens()
if tokens.abort then
error('Execution manually aborted')
end
end加载到lua状态后,我们应该对DoLua函数进行一些更改:
private void DoLua()
{
try
{
state.DoString("while(true) do print(tokens.abort); checkTokens(); end");
}
catch(Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
}https://stackoverflow.com/questions/62463286
复制相似问题