终止 NLua 脚本执行
Terminate NLua script execution
我在我的应用程序中使用 NLua 到 运行 Lua 脚本。我需要实现随时在单独的线程中终止 运行s 脚本的能力,例如用户按下 "Stop" 按钮并且脚本必须立即终止。我读过 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
谢谢。
此方法运行良好,使用 lua_sethook
在执行每一行 lua 代码之前检查要中止的信号:
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);
}
}
我在我的应用程序中使用 NLua 到 运行 Lua 脚本。我需要实现随时在单独的线程中终止 运行s 脚本的能力,例如用户按下 "Stop" 按钮并且脚本必须立即终止。我读过 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
谢谢。
此方法运行良好,使用 lua_sethook
在执行每一行 lua 代码之前检查要中止的信号:
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);
}
}