这个方法工作得相当好,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);
}
}