André Baptista
André Baptista

Reputation: 522

Timer Loop in c#, wait if code isn't completed

I'm trying to implement a timer loop in c# (say each 30 miliseconds a piece of code should run). This isn't so hard, as others questions here in SO have already addressed this issue, like this, or this one.

The trickiest part is that the piece of code can last more than the loop time. In this case I want to wait until it ends (not another 30 ms wait).

Example:

0 ms - First iteration: code completed in 20 ms.

30 ms - Second iteration: code isn't completed in time.

60 ms - wait second iteration code to end. Ended in total 41 ms.

71 ms - Third iteration: code completed in 15 ms.

101 ms - Fourth iteration: code completed in 22 ms.

And so on.

Should I use a Task and check if is completed? What is a fair, elegant way of do that. Any help will be much appreciated. Thanks.

Edit: After a couple of tries, this code seems to work with example code, lets see later with the production code: https://dotnetfiddle.net/cqmTzF

Upvotes: 1

Views: 382

Answers (1)

Serge
Serge

Reputation: 4036

Try something like this:

    public class PeriodicAction
    {
        private int _frequencyMs;
        private readonly Timer _timer;
        private bool _enabled;

        public Action ActionMethod { get; private set; }

        public int FrequencyMs
        {
            get { return _frequencyMs; }
            set
            {
                _frequencyMs = value;
                _timer.Change(0, _frequencyMs);
            }
        }

        public bool Enabled
        {
            get { return _enabled; }
            set
            {
                _timer.Change(value ? 0 : Timeout.Infinite, _frequencyMs);
                _enabled = value;
            }
        }

        public bool IsRunning { get; private set; }

        public PeriodicAction(Action actionMethod, int frequencyMs)
        {
            this.ActionMethod = actionMethod;
            this._frequencyMs = frequencyMs;
            this._timer = new Timer(timerCallbackMethod, null, 0, frequencyMs);
        }

        private void timerCallbackMethod(object sender)
        {
            if (IsRunning) return;

            IsRunning = true;

            ActionMethod();
            _timer.Change(0, _frequencyMs);

            IsRunning = false;
        }
    }

Upvotes: 1

Related Questions