0

Here's a code I made in C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace xyz
{
    class Program
    {
        Thread t1, t2;
        static void Main(string[] args)
        {
            Program go = new Program();
            go.actual();
        }
        public void actual()
        {
            t1 = new Thread(timer);
            t2 = new Thread(inputting);
            t1.Start();
            t2.Start();
        }
        public void timer()
        {
            Thread.Sleep(5000);
            t2.Abort();
            Console.WriteLine("5 seconds passed!");
        }
        public void inputting()
        {
            Console.WriteLine("Please wait 5 seconds...");
            Console.ReadKey();
        }
    }
}

Now, the problem is, when the console says "5 seconds passed!" (after aborting the t2 thread), it doesn't exit right away. This text stays there for a couple of seconds and then the console exits.

The thing is, if I press a key (of the ReadKey method) before the thread aborts, it displays the "5 seconds passed!" text and then it exits right away.

If I don't click any key, and the ReadKey method doesn't happen, it just displays the text for a couple of seconds.

Why is that? Is it a bug? And can I fix it?

Kristof U.
  • 1,263
  • 10
  • 17
BlueRay101
  • 1,447
  • 2
  • 18
  • 29
  • Because it's cleaning up the threads? I can't think of any other reason. – Mike Perrenoud Oct 11 '13 at 12:21
  • Yeah, but if I aborted the thread which has the "Console.ReadKey()", the ReadKey command should be also aborted, since it is a part of the thread I aborted. – BlueRay101 Oct 11 '13 at 12:24
  • 1. Don't abort threads, your just asking for trouble and 2. why are you creating a new instance of `Program`? Just call `actual`. – James Oct 11 '13 at 12:25
  • It still has to cleanup the first thread upon exiting. I'm not sure you've actually been 100% clear on what you're experiencing. You said the text stays there. I wouldn't expect it to leave. But you're acting like it just takes a while for the application to close. You have to be a lot clearer. – Mike Perrenoud Oct 11 '13 at 12:25
  • It should just close immediately. Cannot see anything wrong myself. However, you may want to look into creating the Threads as a `BackgroundThread` so when the main Thread of the application closes these are automatically closed, to stop processing after your application has complete. – Squirrel5853 Oct 11 '13 at 12:28
  • OK, I'll be more clear here. After the "5 seconds passed!" text appears, I expect it to exit immediately, because there is nothing after the "Console.WriteLine". However, after the "5 seconds passed!" text is displayed, I have to press a key to exit, even though I aborted Thread t2, which has the ReadKey in it. – BlueRay101 Oct 11 '13 at 12:34
  • Here's a photo: http://i.imgur.com/gszjVSi.png – BlueRay101 Oct 11 '13 at 12:48
  • See? It just stays there until I press a key, even though I've aborted the thread which contains the ReadKey(). – BlueRay101 Oct 11 '13 at 12:48

2 Answers2

0

The result you are seeing seems reasonable to me, calling Thread.Abort isn't going to somehow unblock the Console so it will still be waiting for input. Regardless, you should avoid calling Thread.Abort as there is no guarantee that it will work as expected. It's a much better approach to build cancellation support into your threads and there are various ways to do this.

Alternatively, just use the Task Parallel Library which has it all build in already.

James
  • 80,725
  • 18
  • 167
  • 237
0

From your comments I see that you basically want to timeout the Console.ReadKey call after a certain amount of time. Unfortunately, ReadKey does not have a timeout parameter. That is okay. We can wrap it in a method that does. You do not need to use any asynchronous mechanisms to accomplish this. Just use Console.KeyAvailable in a synchronous polling loop.

public static class ConsoleEx
{
  public static bool TryReadKey(TimeSpan timeout, out ConsoleKeyInfo keyinfo)
  {
    var cts = new CancellationTokenSource();
    return TryReadKey(timeout, cts.Token, out keyinfo);
  }

  public static bool TryReadKey(TimeSpan timeout, CancellationToken cancellation, out ConsoleKeyInfo keyinfo)
  {
    keyinfo = new ConsoleKeyInfo();
    DateTime latest = DateTime.UtcNow.Add(timeout);
    do
    {
        cancellation.ThrowIfCancellationRequested();
        if (Console.KeyAvailable)
        {
            keyinfo = Console.ReadKey();
            return true;
        }
        Thread.Sleep(1);
    }
    while (DateTime.UtcNow < latest);
    return false;
  }
}

And then you would use it like this.

public static void Main()
{
  ConsoleKeyInfo cki;
  if (ConsoleEx.TryReadKey(TimeSpan.FromSeconds(5), out cki))
  {
    Console.WriteLine("ReadKey returned a value.");
  }
  else
  {
    Console.WriteLine("ReadKey timed out.
  }
}
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150