EriqaBana
EriqaBana

Reputation: 125

How do you create a timer that starts with a delay and with stopwatch in C#

I'm having issues creating a timer that when started will first sleep for 2 minutes. It will run for 5 minutes total and every minute will do work. This is what I have:

class Program{
    static System.Timers.Timer aTimer;
    static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    static TimeSpan LongToRun = new TimeSpan(0,300,0)); //run for 5 minutes

    static void Main (string[] args){
        Thread.Sleep(120000); //sleep for 2 mins
        sw.Reset();
        sw.Start();
        Start();
    }

    static void Start()
    {
        aTimer = new System.Timers.Timer();
        aTimer.Interval = 60000;  //every min
        aTimer.Enabled = true;
        aTimer.Elapsed += new ElapsedEventHandler(timer_Elapsed); 
        aTimer.Start();

    }

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        TimeSpan ts = sw.Elapsed;
        if (ts.TotalSeconds >= LongToRun.TotalSeconds)
        {
            aTimer.Stop();
            return;
        }

        DoWork();
    }
}   

timer_Elapsed never is called... Am I going about this wrong?

Upvotes: 0

Views: 1487

Answers (3)

Harald Coppoolse
Harald Coppoolse

Reputation: 30464

Your Start procedure returns immediately after it started the timer and returns to your main program. The main program ends and the timer that was still running is finalized before it elapses.

Solution: make sure your program is running long enough for your timer to elapse.

  • The main program creates a System.Threading.ManualResetEvent before starting the timer
  • After starting the timer it waits for the ManualResetEvent to be set using ManualResetEvent.WaitOne()
  • At the end of your timer_elapsed function the function raises the event using ManualResetEvent.Set
  • The thread in the main program that waited for this event continues processing.

Another problem is that you subscribe to the event after you started your timer. This is probably not a cause of the problem, but neat code would be to subscribe before you start the timer.

By the way, the timer class implements IDisposable. This means that the designer of this class informs you he uses scarce resources that need to be freed as soon as possible. Consider Disposing the Timer class as soon as it is not needed anymore. The using (...) statement is ideal for this.

Using async-await would make your code much easier to read and to maintain.

Consider the following code:

public static void Main()
{
    Thread.Sleep(TimeSpan.FromMinutes(2));
    var myTask = Task.Run( () => WorkerTask())
    Task.Wait(myTask);
}

private static TimeSpan longToRun = new TimeSpan.FromMinutes(5);
// easier to read than new TimeSpan(0,300,0));

public static async Task WorkerTask()
{
    StopTime = DateTime.Now + longToRun;

    // repeatedly wait a while and DoWork():
    while (DateTime.Now < StopTime)
    {
        await Task.Delay(TimeSpan.FromMinutes(2);
        DoWork();
    }
}

That's all, No need for ManualResetEvents, no Stopwatches, no Timers nor timer_elapsed event handlers.

It is even quite easy to pass parameters to procedure WorkerTask(), and cancelling the event for instance because the operator presses < esc > is easy if you create a CancellationTokenSource and pass a CancellationToken to the WorkerTask as a parameter. In fact, that would make the code even more simpler:

public static void Main()
{
    Thread.Sleep(TimeSpan.FromMinutes(2));
    using (var tokenSource = new CancellationTokenSource())
    {
        var myTask = Task.Run( () => WorkerTask(tokenSource.Token))
        tokenSource.CancelAfter(TimerSpan.FromMinutes(5));
        // instead of LongToRun
        Task.Wait(myTask);
    }
}

public static async Task WorkerTask(CancellationToken token)
{
    // repeatedly wait a while and DoWork():
    while (!token.IsCancellationRequested)
    {
        await Task.Delay(TimeSpan.FromMinutes(2, token);
        DoWork();
    }
}

More information:

Upvotes: 1

Sergey_T
Sergey_T

Reputation: 588

First of all, you've set incorrect period:

static TimeSpan LongToRun = new TimeSpan(0,**5**,0)); //run for 5 minutes

timer_Elapsed is never called because your application is closed earlier. Add Console.ReadLine() at the end.

static void Main (string[] args){
        Thread.Sleep(120000); //sleep for 2 mins
        sw.Reset();
        sw.Start();
        Start();
        Console.ReadLine();
    }

Upvotes: 0

Ranju Jacob
Ranju Jacob

Reputation: 1

As Sergey pointed out there is a mistake in the time period set in Timespan LongToRun. I have tried a cod with just Thread.sleep function. Hope the code is helpful for you.

class Program {
    static System.Timers.Timer aTimer;
    static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    static TimeSpan LongToRun = new TimeSpan(0,5,0); //run for 5 minutes

    static void Main (string[] args)    {
        Console.WriteLine("Start Of Program" + DateTime.Now);
        Thread.Sleep(120000); //sleep for 2 mins
        sw.Reset();
        sw.Start();
        Start();
    }

    static void Start() {
        TimeSpan ts = sw.Elapsed;
        while (ts.TotalSeconds < LongToRun.TotalSeconds) {
            doWork();
            Thread.Sleep(60000);
            ts = sw.Elapsed;
        }
        Console.WriteLine("End of program");
        Console.ReadLine();
    }

    static void doWork() {
         Console.WriteLine(DateTime.Now);
    }
}  

Upvotes: 0

Related Questions