Home > database >  Wait for timer tick in another thread
Wait for timer tick in another thread

Time:08-08

I am using a simple Lua interpreter to allow the user to move a robotic arm in the real world with a C# program.

The move function in Lua should be blocking (and return only once the movement is completed) so that the program is as simple as possible to write and understand for the user. I am trying to write this blocking function in C#.

To keep things simple, let's say that I can read the state of the robot in a file with a timer. Essencially, the function should "wait" for the timer tick and then choose to return or to keep waiting. I know that sounds weird, but hopefully you understand what I need. Here is a simplified version of what my code looks like:

using Neo.IronLua;

namespace WinFormsApp5 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();

            // Timer
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.Interval = 500;
            timer.Elapsed  = Timer_Elapsed;
            timer.Start();

            // Interpreter
            using (Lua l = new Lua()) {
                var g = l.CreateEnvironment();
                dynamic dg = g;
                dg.move = new Action<int, int, int>(move);                   // ↓ calling the function from Lua
                Task.Factory.StartNew(() => g.DoChunk("print('Hello World!'); move(5, 5, 10)", "test.lua")); // using a task not to block the UI thread
            }
        }

        private static void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) {
            System.Diagnostics.Debug.WriteLine("timer tick");
            try {
                if (System.IO.File.ReadAllText("state.txt") != "moving") {
                    // tell the move function to return
                }
            } catch { }
        }

        public static void move(int x, int y, int z) {
            System.Diagnostics.Debug.WriteLine($"start {x} {y} {z}");
            Thread.Sleep(2000); // wait here for the movement to finish
            System.Diagnostics.Debug.WriteLine("done");
        }
    }
}

Is there a way to achieve such a behaviour using things like tasks, async, await ? I am new to asynchronous programming and threading. Any help would be appreciated.

CodePudding user response:

What about using a ManualResetEventSlim?

Your code might look like:

private readonly ManualResetEventSlim _movementFinished = new();

private static void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) {
    System.Diagnostics.Debug.WriteLine("timer tick");
    try {
        if (System.IO.File.ReadAllText("state.txt") != "moving" &&
            !this._movementFinished.IsSet) {
            this._movementFinished.Set();
        }
    } catch { }
}

public static void move(int x, int y, int z) {
    this._movementFinished.Reset();
    
    System.Diagnostics.Debug.WriteLine($"start {x} {y} {z}");
    // Thread.Sleep(2000); // wait here for the movement to finish
    this._movementFinished.Wait();
    System.Diagnostics.Debug.WriteLine("done");
}

This looks strange and maybe you need a logic that ensures that moving is in the state.txt-file to prevent unexpected behaviour.

Btw: Your Ctor looks weird because you create a disposable Lua-instance, run a task but your lua-instance might be freed much earlier that the task finishes.

CodePudding user response:

You could use Thread.join. This waits for the Thread. Read THIS for more Information

HERE is a good example

  • Related