Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass System.Threading.Timer object reference to its callback function

Tags:

c#

.net

timer

is it possible to pass the System.Threading.Timer object reference to its callback function, something like this:

System.Threading.Timer myTimer = new System.Threading.Timer(new TimerCallback(DoSomething), myTimer, 2000, Timeout.Infinite);

Because in "DoSomething" method I want to call:

myTimer.Change(5000, Timeout.Infinite);

I'll paste a draft console application below. Idea is this: I have List of timers. And every timer makes some request and when it receives it, it changes some shared data. But, I can't pass the reference to timer into its callback, nor can I use it's index, because it becomes "-1" for some reason(investigating)..

using System;
using System.Collections.Generic;
using System.Threading;

namespace TimersInThreads
{
    class Program
    {
        public static int sharedDataInt;
        static private readonly object lockObject = new object();
        public static List<System.Threading.Timer> timers = new List<Timer>();

        static void Main(string[] args)
        {
            System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
            timers.Add(timer);

            System.Threading.Timer timer2 = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
            timers.Add(timer2);

            System.Threading.Timer timer3 = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
            timers.Add(timer3);

            //timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 1", 1000, Timeout.Infinite);
            //timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 2", 450, Timeout.Infinite);
            //timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 3", 1500, Timeout.Infinite);

            Console.ReadLine();

        }

        static void DoSomething(object timerIndex)
        {
            // Request
            // Get Response
            var x = getSomeNumberWithDelay();


            // Executes after Response is received
            lock (lockObject)
            {
                sharedDataInt++;
                Console.WriteLine("Timer" + (int)timerIndex + ", SHaredDataInt: " + sharedDataInt + "\t\t" + DateTime.Now.ToString("HH:mm:ss tt") + "." + DateTime.Now.Millisecond.ToString());
            }

            timers[(int)timerIndex].Change(5000, Timeout.Infinite);
        }

        static int getSomeNumberWithDelay()
        {
            Thread.Sleep(5000);
            return 3;
        }
    }
}

Please, give me some idea or advice. Much appreciated, thanks!

like image 794
Aremyst Avatar asked Feb 14 '23 08:02

Aremyst


2 Answers

The state parameter in the Timer constructor is passed as an argument to the TimerCallback - this is just an object therefore will work with anything, including the timer reference itself.

So

new System.Threading.Timer(new TimerCallback(DoSomething), myTimer, 2000, Timeout.Infinite);

is perfectly acceptable. In your callback you would just need to cast the parameter as Timer e.g.

static void DoSomething(object state)
{
    ...
    var timer = (System.Threading.Timer)state;
}

Looking at your problem again, I see what you are trying to do is pass the timer as a parameter into it's constructor (which obviously can't be done as it hasn't been officially declared yet). You can workaround this though by passing the timer to the callback explicitly e.g.

Timer t = null;
t = new Timer(delegate { DoSomething(t); }, null, 2000, Timeout.Infinite);

By the time the callback is triggered t will set to the reference of the timer.

like image 163
James Avatar answered Feb 16 '23 03:02

James


Replace each occurrence of timers.Count - 1 with timers.Count:

System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count, 2000, Timeout.Infinite);
timers.Add(timer);

When you adding first timer to the list, there is no elements there, so the timers.Count equals to 0.

Alternative way is to pass an instance of particular timer as the second argument of the callback instead of its index.

like image 27
Dmitry Avatar answered Feb 16 '23 03:02

Dmitry