Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Console application (C#) is stuck while interaction

I’m writing console application which does some work by scheduler and write output to console. Everything is good but when I click on the console it stops working and waits for my right click. After that it continues working.

I thought that it simply doesn’t write text to console and does what it needs to do but no, it waits my interaction. I can rewrite this code to WinForms or WPF but I think it can be solved in another way. Here my code

    static void Main(string[] args)
    {
        Console.WriteLine("Started...");
        var timer = new System.Timers.Timer(1000);
        timer.Elapsed += timer_Elapsed;
        timer.Start();

        Console.ReadLine();
    }

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("Writing to file " + DateTime.Now.ToString());
        System.IO.File.AppendAllLines(@"C:\Temp\log.txt", 
          new[] { DateTime.Now.ToString()});
    }

After clicking on console it stops appending time to file log.txt. Any ideas how to fix that? Thanks.

like image 873
Tarun Khamar Avatar asked Apr 15 '17 16:04

Tarun Khamar


People also ask

What is console application C?

A console application, in the context of C#, is an application that takes input and displays output at a command line console with access to three basic data streams: standard input, standard output and standard error.

What is console application example?

Console-based applications include Alpine (an e-mail client), cmus (an audio player), Irssi (an IRC client), Lynx (a web browser), Midnight Commander (a file manager), Music on Console (an audio player), Mutt (an e-mail client), nano (a text editor), ne (a text editor), newsbeuter (an RSS reader), and ranger (a file ...

How do I open the console application?

Select the Calculator button or press F5 to run your app. A console window opens.

How do I close the console app C?

You can use Environment. Exit(0) and Application. Exit .


2 Answers

That’s standard console behavior, it waits your user input locking the execution thread. To understand why it is look at Console.Write implementation. It simply writes to Console output (Console.Out property) which is by default synchronized TextWriter (source). So, the “magic” is here.

You can solve this by delegating console writing to dedicated thread. For instance in his way:

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Writing to file " + DateTime.Now.ToString());
        });
        System.IO.File.AppendAllLines(@"C:\Temp\log.txt", 
          new[] { DateTime.Now.ToString()});
    }

So, your application will continue writing to file but will write text to console only when you do right click. The problem of this implementation is that it can create a lot threads increasing ThreadPool.

Better implementation can be done for instance with some special TaskScheduler like with SequentialScheduler

    static TaskFactory factory = new TaskFactory(new SequentialScheduler());

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        factory.StartNew(() =>
        {
            Console.WriteLine("Writing to file " + DateTime.Now.ToString());
        });
        System.IO.File.AppendAllLines(@"C:\Temp\log.txt", 
         new[] { DateTime.Now.ToString()});
    }

It won’t increase ThreadPool. Another implementation also can be used but the main idea is – delegating console write to another thread which may be blocked by user, the working thread will be unblocked and continue working.

like image 103
Vasyl Zv Avatar answered Sep 26 '22 23:09

Vasyl Zv


Advice on implementation

If you want to avoid putting a lot of work on the thread-pool for the simple purpose of writing some stuff to console, then queues are your friend. This also ensures the correct order of the messages, and gives you some additional control (like disposing of unimportant entries).

Create a console logger thread which reads off of a concurrent queue where you enqueue entries to write to the console. Do take note that if the console is blocked indefinitely, then the queue will eventually grow until you run out of memory -- that is if you do in fact enqueue millions of entries in that time.

Example:

    static ConcurrentQueue<string> consoleQueue = new ConcurrentQueue<string>();
    static ManualResetEventSlim itemEnqueuedEvent = new ManualResetEventSlim();

    static void WriteToConsoleLoop(object state)
    {
        var token = (CancellationToken)state;
        while (!token.IsCancellationRequested)
        {
            string entry;
            while (consoleQueue.TryDequeue(out entry))
            {
                Console.WriteLine(entry);
            }
            try
            {
                itemEnqueuedEvent.Wait(token);
                itemEnqueuedEvent.Reset();
            }
            catch (OperationCanceledException)
            {
                break;
            }
        }
    }

    static void WriteToConsole(string entry)
    {
        consoleQueue.Enqueue(entry);
        itemEnqueuedEvent.Set();
    }

    static void Main(string[] args)
    {
        var cts = new CancellationTokenSource();
        // Background or foreground, depends on how vital it is
        // to print everything in the queue before shutting down.
        var thread = new Thread(WriteToConsoleLoop) { IsBackground = true };
        thread.Start(cts.Token);

        WriteToConsole("Started...");

        // Do your stuff...

        cts.Cancel();
    }
like image 30
odyss-jii Avatar answered Sep 25 '22 23:09

odyss-jii