amartin94 amartin94 - 3 months ago 26
C# Question

Timer Class not Firing before End of Program

So i've attempted to modify the code block posted by Sriram Sakthivel here:

C#: How to start a thread at a specific time

public class Program
{
static Boolean checkIn = false;

public static void checkInCycle()
{
checkIn = SynchronousSocketClient.StartClient();

if(checkIn == false)
{
// Use TimeSpan constructor to specify:
// ... Days, hours, minutes, seconds, milliseconds.
TimeSpan span = new TimeSpan(00, 00, 30);

//SetUpTimer(span);
DateTime current = DateTime.Now;
TimeSpan triggerTime = current.TimeOfDay + span;

SetUpTimer(triggerTime);
}
if(checkIn == true)
{

//Do some processing
}



}

public static void SetUpTimer(TimeSpan alertTime)
{
//DateTime current = DateTime.Now;
//TimeSpan timeToGo = alertTime - current.TimeOfDay;

TimeSpan timeToGo = alertTime;
Console.WriteLine("Checking in at: " + timeToGo);

if (timeToGo < TimeSpan.Zero)
{
return; //time already passed
}
System.Threading.Timer timer = new System.Threading.Timer(x =>
{
Console.WriteLine("Running CheckIn Cycle");
checkInCycle();

}, null, timeToGo, Timeout.InfiniteTimeSpan);

}

public static int Main(String[] args)
{
checkInCycle();

Console.WriteLine("End of Program Reached");
Console.ReadLine();

return 0;

}
}


However instead of specifying an exact time to run at, i've attempted to add 30 mins onto the current time in an attempt to make a client service that will remain alive for x amount of minutes before attempting to connect again. Right now, for simplicity/testing sake i have it set to run checkInCycle every 30 seconds if it cant connect to the server.

Upon first check SynchronousSocketClient.StartClient(); succesfully returns false if the server is down, and will enter the if(checkIn == false) loop - however, after setting up a timer it moves on to process the rest of the main loop, and waits at the end without triggering and rescheduling a timer.

Any ideas as to why this is happening? Also I understand i could just sleep the main thread for x amount of minutes before rechecking again, but the client could be asleep for up to several hours and because of this i have heard that timers are more efficient, is this the case?

Answer

This is happening because at the end of your execution of the main() method you are losing the reference to your System.Threading.Timer. The new System.Threading.Timer call does not block the main thread while it waits to run its code.

In the above reference (second note under Remarks), the documentation explains that a reference must be maintained (as with all managed code) for it not to be disposed of by the Garbage Collector.

As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.

The way you can keep this simple program is if you use a System.Threading.Monitor and perform a Wait() directly after the checkInCycle() function call in the main() function. Then Pulse() when you want to proceed.

You may want to read up on thread synchronization or concurrency further if you are curious about any more in-depth topics on performing asynchronous calls or operating in a mutli-threaded environment.

*edited for clarification.