Gaspa79
Gaspa79

Reputation: 5689

Prevent my console application from closing after a .Net.Timer starts

So I have this simple code:

static void Main(string[] args)
  {
      var timer = new Timer(0.5 * 60 * 1000); // 0.5 minutes times 60 seconds times 1000 miliseconds
      timer.Elapsed += new System.Timers.ElapsedEventHandler(Start);
      timer.AutoReset = true;            
      timer.Start();
  }

Which starts a timer that starts the whole program logic. Problem is, the console application closes and nothing is done. How do I prevent this? I know that if I do something like while(true) it works, but that does not seem like an elegant/proper solution.

Upvotes: 5

Views: 3221

Answers (5)

Michael
Michael

Reputation: 1276

The last answer is 7 years old. In the meantime, methods from System.Threading like Timer, Sleep, ... should not be used anymore. They carry the risk of deadlocks, and I have to warn against their use especially in ASP.NET Core.

There are several things to consider:

  • No program runs forever. What happens when the program should be closed (by a shutdown or a signal)?
  • The termination must be implemented in your program logic. Many async .NET Core methods supports a CancellationToken as a parameter.

There are 2 approaches to create an "endless" program:

  • Worker Services in .NET Core are the common approach today to write programs that should run permanently as a service. They can be registered as Windows Service. More Infos on learn.microsoft.com and devblogs.microsoft.com if you want to register your service as a "real" service.
  • If you need a "real" console application that performs tasks in the foreground, this can be done with the following sample code:
using System;
using System.Threading.Tasks;
using System.Threading;

namespace DemoApp
{
    internal class Program
    {
        private static int _isRunning = 0;

        private static async Task Main(string[] args)
        {
            // No program can run infinitely. We always have to provide a mechanism for termination.
            var tcs = new CancellationTokenSource();
            var periodTimeSpan = TimeSpan.FromSeconds(10);

            // This mechanism is CTRL+C, so we catch this.
            Console.CancelKeyPress += (sender, e) =>
            {
                tcs.Cancel();
                e.Cancel = true;
            };

            try
            {
                // No endless loop. We are checking for a cancellation request!
                while (!tcs.IsCancellationRequested)
                {
                    // Perform your work.
                    var task1 = Run(tcs.Token);
                    var task2 = Task.Delay(periodTimeSpan, tcs.Token);
                    // If the execution time of Run is greater than periodTimeSpan, we will wait. Depends on your needs.
                    await Task.WhenAll(task1, task2);
                }
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("User canceled your app.");
            }
        }

        private static async Task Run(CancellationToken token)
        {
            // Should never occur if you use WhenAll()
            if (Interlocked.Exchange(ref _isRunning, 1) == 0)
            {
                // Perform your work.
                _isRunning = 0;
            }
        }
    }
}

Upvotes: 3

Daniel Kotin
Daniel Kotin

Reputation: 326

If you want to just run a timer and wait, then Console.Read() is your friend.

The reason why your code is terminating is because the function initializes the timer, starts it and then ... hits the end of the Main function. As a result, the function exits.

The current code doesn't do anything useful (besides starting a timer which is ignored).

If you want to see your timer in action, do some other work after you start the timer. Then, stop the timer after an interval and print it/evaluate it how you deem fit. (The timer doesn't run on the main thread, whereas something like Console.Read() will be on the main thread and thus, block the thread until you have input)

Upvotes: 1

Allan Elder
Allan Elder

Reputation: 4094

Add a Console.ReadKey(); this will allow you to close the console window by pressing any key.

    static void Main(string[] args)
    {
        var timer = new Timer(0.5 * 60 * 1000); // 0.5 minutes times 60 seconds times 1000 miliseconds
        timer.Elapsed += new System.Timers.ElapsedEventHandler(Start);
        timer.AutoReset = true;            
        timer.Start();

        Console.ReadKey();
    }

Upvotes: 1

Thomas Weller
Thomas Weller

Reputation: 59259

Your console application does not end because the timer starts. It ends because the program reaches the end of the Main() method.

Whatever action you take to prevent the program from exiting Main() will help. While many proposed solutions actually do this. I wanted to highlight the fact that it's not the timer causing the issue.

Upvotes: 0

Paweł Bejger
Paweł Bejger

Reputation: 6366

Maybe try

Console.Read(); 

At the end of the code

Thanks to this your console window will not be closed as long as a user will not press a key.

Upvotes: 10

Related Questions