David C February 2016

Multiple timer/callbacks — best approach to prevent duplicates and to monitor them

I have a c# console, that I have made into a Windows service, which I would like to run reliably and constantly.

  1. I want to prevent overlap of the same timer firing again
  2. I want to prevent different timers trying to use the same resource at once
  3. I want to be able to monitor the timers and interact with then.

It has a few aspects to it. Each runs very regularly. I have previously read about TaskScheduler vs Windows Service running this kind of thing, and have opted for this approach because something is running almost constantly.

  • TaskType1
  • TaskType2
  • TaskType3
  • TaskType4

I'm using timer callbacks, each with their own, similar to this simplified version:

class Program
{
    static PollingService _service;

    static void Main()
    {
        _service = new PollingService();

        TimerCallback tc1 = _service.TaskType1;
        TimerCallback tc2 = _service.TaskType2;
        TimerCallback tc3 = _service.TaskType3A;
        TimerCallback tc4 = _service.TaskType3B;

        Timer t1 = new Timer(tc1, null, 1000, 5000);
        Timer t2 = new Timer(tc2, null, 2000, 8000);
        Timer t3 = new Timer(tc3, null, 3000, 11000);
        Timer t4 = new Timer(tc4, null, 4000, 13000);


        Console.WriteLine("Press Q to quit");
        while (Console.ReadKey(true).KeyChar != 'q')
        {
        }
    }
}

class PollingService
{
    public void TaskType1(object state)
    {
        for (int i = 1; i <= 10; i++)
        {
            Console.WriteLine($"TaskOne numbering {i}");
            Thread.Sleep(100);
        }
    }

    public void TaskType2(object state)
    {
        for (int i = 10; i <= 100; i++)
        {
            Console.WriteLine($"TaskTwo numbering {i}");
            Thread.Sleep(100);
        }
    }

    public void TaskType3A(object state)
    {
        Increment(200000000        

Answers


Haukinger February 2016

  1. basically, yes, or AutoResetEvent
  2. you can stop it, wait for the resource to free up, and then restart it
  3. keep a list of states associated with your timers, and update those states from the timers (set to running when starting, set to waiting when done, or something along these lines)


TomTom February 2016

1: Likely the best is not to do anything in the timers but stat a task - IF any WHEN a flag is set or not set. Look for interlocked (the class) on how to implement that without locking.

2: Monitor. But seriously, why do they share an EF contect?

3: Sure. Create performance counters. Monitor them. The API is in windows for many many years.


Brandon February 2016

If you have to make sure that each thread doesn't have any overlap, you can use the Timer.Change(int, int) method to stop executing at the start of the callback, and then resume it at the end of the callback. You can also do some magic with a ManualResetEvent for each thread but it'll get messy.

I'm not a fan of timers for threading and try to avoid them whenever I can. If you can sacrifice the "each thread must run after n seconds", do it. Use tasks with a cancellation token instead, it will solve your overlap problem. For example:

A.

public class Foo
{
    private CancellationTokenSource _cts;
    //In case you care about what tasks you have.
    private List< Task > _tasks;

    public Foo()
    {
        this._cts = new CancellationTokenSource();

        this._tasks.Add(Task.Factory.StartNew(this.Method1, this._cts.Token));
        this._tasks.Add(Task.Factory.StartNew(this.Method2, this._cts.Token));
        this._tasks.Add(Task.Factory.StartNew(this.Method3, this._cts.Token));
        this._tasks.Add(Task.Factory.StartNew(this.Method4, this._cts.Token));


    }

    private void Method1(object state)
    {
        var token = (CancellationToken) state;
        while ( !token.IsCancellationRequested )
        {
            //do stuff
        }

    }
    private void Method2(object state)
    {
        var token = (CancellationToken)state;
        while (!token.IsCancellationRequested)
        {
            //do stuff
        }
    }
    private void Method3(object state)
    {
        var token = (CancellationToken)state;
        while (!token.IsCancellationRequested)
        {
            //do stuff
        }
    }
    private void Method4(object state)
    {
        var token = (CancellationToken)state;
        while (!token.IsCancellationRequested)
    

Post Status

Asked in February 2016
Viewed 3,208 times
Voted 6
Answered 3 times

Search




Leave an answer