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);
}
}
Nluai set up a variable that i would set to true when theABORTbutton was pressed by the operatorenv["ABORT"] = this.abortthis variable was check in the codes lowest function where the code spent most of it's time. the press was not detected "immediately" but between 0-250ms after, this specific system also was equipped with a hardware emergency stop that cut power from the system when pressed, all systems that are required to stop should have a hardware stop as software will never be 100% reliable, is the input device damage, is the pc frozen, etc.