-1

I write this code:

 Timer timer = new Timer(Callback, "", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(20));

But only execute the callback method once. I need to execute the callback method each 20 seconds.

Rand Random
  • 7,300
  • 10
  • 40
  • 88
  • 1
    You need to declare the timer somewhere where the GC wont find it - if you declare in in some scope that you leave if will be eaten by it – Patrick Artner Feb 09 '18 at 17:50
  • 1
    First, there are 3-5 different TImers in .NET. I do not know how many in .NET Core and Mono. Each of them behaves differently. Seconds, where are you writing this? A common beginner mistake is trying to learn timers or Multitasking/Threading with a console application. With GUI's it is a lot easier. – Christopher Feb 09 '18 at 17:52
  • @PatrickArtner: The GC is not exactly know to be agressive with freeing up memory. If the programm does little else, it could be around for hours of runtime. ideally it only runs at application closure, because then it does the least work with the greatest effect and least amount of Applciation stalling (https://social.msdn.microsoft.com/Forums/en-US/286d8c7f-87ca-46b9-9608-2b559d7dc79f/garbage-collection-pros-and-limits?forum=csharpgeneral) – Christopher Feb 09 '18 at 17:54
  • @Christopher - or it might not. – Patrick Artner Feb 09 '18 at 17:56
  • @PatrickArtner: we have no information that this is not a Class scope variable. At wich point it would not be cleaned up before the class is recyceled. – Christopher Feb 09 '18 at 17:58
  • @Christopher and we have no evidence that this is not a function scoped variable which would be allowed to be cleanex up with a gen0 GC, which do happen frequently. https://stackoverflow.com/questions/18136735/can-timers-get-automatically-garbage-collected – Scott Chamberlain Feb 09 '18 at 18:08

2 Answers2

2

Demonstrating the effect of garbage collecting on "out of scope" timer that is no longer remembered by any instance:

static void Main(string[] args)
{
    System.Threading.Timer timer = new System.Threading.Timer(o => { Console.WriteLine(DateTime.Now); }, "", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));

    if (true)
    {
        // declared here and soon out of scope but works until garbage collected.
        new System.Threading.Timer(o => { Console.WriteLine($"Inner {DateTime.Now}"); }, "", TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2));
    }

    Console.ReadLine();  //  wait 5-6 printouts, hit return once

    // force garbage collection. This happens from time to time by itself when your
    // ressources gets scarce and C# runtime "thinks" it is time to GC. 
    GC.Collect();
    GC.WaitForPendingFinalizers();

    Console.ReadLine();  //  wait some more .. only 1 timer prints anymore
}

Output:

09.02.2018 18:57:27
Inner 09.02.2018 18:57:27
09.02.2018 18:57:29
Inner 09.02.2018 18:57:29
09.02.2018 18:57:31
Inner 09.02.2018 18:57:31      // hit retun once

09.02.2018 18:57:33
09.02.2018 18:57:35
09.02.2018 18:57:37
09.02.2018 18:57:39

You can avoid GC by declaring your timer not locally but as a member of a class-instance that sticks around, GC only "removes" things that are no longer referenced (simplified explanation). A member of a class will stay "ticking" as long as you have a "live" instance of this class around.

See/read garbage-collection:

As long as address space is available in the managed heap, the runtime continues to allocate space for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection in order to free some memory. The garbage collector's optimizing engine determines the best time to perform a collection, based upon the allocations being made.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

Assuming you are using a System.Threading.Timer it should work if (as others have said) the timer does not go out of scope and get disposed/GC'd. Here is a console app showing it in action:

class Program
{
    class TimerTest
    {
        private Timer timer1;

        private void Callback1(object state)
        {
            Console.WriteLine("Callback1");
        }
        private void Callback2(object state)
        {
            Console.WriteLine("Callback2");
        }

        public TimerTest()
        {
            // Class scoped timer
            timer1 = new Timer(Callback1, "", TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.20));

            // Function scoped Timer (force displose with using)
            using (Timer timer2 = new Timer(Callback2, "", TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.20)))
            {
                // Give some time for timer2 callbacks
                Thread.Sleep(500);
            }
        }
    }


    static void Main(string[] args)
    {
        TimerTest test = new TimerTest();

        while (true) Thread.Sleep(1000);
    }
}

Here is the results:

Callback2
Callback1
Callback2
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
Callback1
...
Marker
  • 972
  • 6
  • 9