This method works reasonably well, using the lua_sethook
to check for signal to abort before executing each line of lua code:
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);
}
}
}
this ofcourse comes at the cost of some added overhead for every line, to reduce that you can change the hook one of the other values.
Another option is to use tokens that the lua thread would watch and then abort as needed, this method does require some handling within the lua script:
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)");
}
Now often your lua execution will be more complex, containing many nested loops, and in those cases you can implement a function in lua to check the tokens and throw an error when the token is true:
function checkTokens()
if tokens.abort then
error('Execution manually aborted')
end
end
with that loaded into the lua state we should make some changes to the DoLua
function:
private void DoLua()
{
try
{
state.DoString("while(true) do print(tokens.abort); checkTokens(); end");
}
catch(Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK);
}
}