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.
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.
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.
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
...