C# Console program end before async function finished

T.Zacks 3,996 Reputation points
2021-08-08T10:04:36.51+00:00

I have simple program where i am calling my main function Start() from timer after every 10 minutes.

i have seen that my main function is getting hit but suddenly finish before executing whole function code.i am confused and not able to understand why this is happening. please guide me what i am missing in my code.

class Program
{
    public static bool IsRunning =false;

    static void Main(string[] args)
    {
        var startTimeSpan = TimeSpan.Zero;
        var periodTimeSpan = TimeSpan.FromMinutes(10);

        var timer = new System.Threading.Timer((e) =>
        {
            Run();
        }, null, startTimeSpan, periodTimeSpan);
    }

        static async void Run()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                ModelCompare oCompare = new ModelCompare();
                var task1 = oCompare.Start();
                await Task.WhenAll(task1);
                IsRunning = false;
            }
        }
}

public class ModelCompare
{
    public async Task<bool> Start()
    {
        //lots of line here to execute and at the end return true
        //return Task.FromResult(true);

        return true;
    }               
}

Thanks

EDIT

Found another good 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 have to provide a mechanism for safe termination.
            var tcs = new CancellationTokenSource();
            var startTimeSpan = TimeSpan.Zero;
            var periodTimeSpan = TimeSpan.FromMinutes(10);

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

            try
            {
                await Task.Delay(startTimeSpan, tcs.Token);
                // 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)
            {
                ModelCompare oCompare = new ModelCompare();
                await oCompare.Start(token);
                // More work...
                _isRunning = 0;
            }
        }
    }

    public class ModelCompare
    {

        public async Task<bool> Start(CancellationToken token)
        {
            // Use
            //     token.ThrowIfCancellationRequested();
            // to check at suitable moments if the user wants to abort.
            return true;
        }
    }
}
Developer technologies | C#
{count} votes

Accepted answer
  1. Adnan Dedic 406 Reputation points
    2021-08-08T17:25:11.487+00:00

    Hi,
    The problem is that the main thread will exit and console app will close once when "Main" method execution completes.
    You have to keep the main thread alive, and there are many different ways to do that. For example, by putting Console.Read* at line 14.

    Console.WriteLine("Press any key to exit");
    Console.ReadKey();
    

    BR,
    Adnan

    2 people found this answer helpful.
    0 comments No comments

3 additional answers

Sort by: Most helpful
  1. Karen Payne MVP 35,586 Reputation points Volunteer Moderator
    2021-08-08T12:23:57.91+00:00

    See if looking at the following examples might help while they are working conceptual examples that don't match your logic completely. Note the Task.Delay is to simulate a long running process.

    Update: Added WhenAll example

    See this repository for full source

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using AsyncSimple.Classes;
    using static AsyncSimple.Classes.GlobalStuff;
    using TimeSpan = System.TimeSpan;
    
    namespace AsyncSimple
    {
        class Program
        {
            private static readonly CancellationTokenSource _cancellationSource = new();
            static async Task Main(string[] args)
            {
                Console.WriteLine("Return bool");
                var example1Result = await Example1();
                Console.WriteLine($"\t{example1Result.ToYesNo()}");
    
                Console.WriteLine();
                Console.WriteLine("Return list");
    
                var customersList = await Example2();
    
                foreach (var customer in customersList)
                {
                    Console.WriteLine($"\t{customer}");
                }
    
                Console.WriteLine();
                Console.WriteLine("Iterator");
                await Example3();
    
    
                var startTimeSpan = TimeSpan.Zero;
                var periodTimeSpan = TimeSpan.FromSeconds(20);
    
                Console.WriteLine();
                Console.WriteLine("Last example");
                var timer = new Timer(async (e) =>
                {
                    var x = await Example1();
    
                    Console.WriteLine(x.ToYesNo());
    
                }, null, startTimeSpan, periodTimeSpan);
    
                Console.ReadLine();
            }
    
            public static async Task<bool> Example1()
            {
                return await Task.Run(async () =>
                {
                    await Task.Delay(5000);
                    return true;
                });
    
            }
    
            public static async Task<List<Customers>> Example2()
            {
                return await Task.Run(async () =>
                {
                    await Task.Delay(1);
                    return MockedData.MockedInMemoryCustomers();
                });
    
            }
    
            private static async Task Example3()
            {
                try
                {
                    await foreach (var item in 10.RangeAsync(MaxNumber, _cancellationSource.Token).WithCancellation(_cancellationSource.Token))
                    {
                        Console.WriteLine($"\t{item}");
                    }
    
                    ;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
    
    1 person found this answer helpful.
    0 comments No comments

  2. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2021-08-08T18:05:04.287+00:00

    If you don’t want to use a keyboard hack, use a signal (AutoResetEvent). See example

    https://learn.microsoft.com/en-us/dotnet/api/system.threading.timer?view=net-5.0

    0 comments No comments

  3. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2021-08-08T18:05:04.493+00:00

    If you don’t want to use a keyboard hack, use a signal (AutoResetEvent). See example

    https://learn.microsoft.com/en-us/dotnet/api/system.threading.timer?view=net-5.0

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.