10

My console app is executing a thread that is totally devoted to the user interface, it spends a lot of its time blocking on Console.ReadLine() (this call spends its time deep within the bowels of Windows, outside the control of the .NET framework).

I need to abort this thread. However, the following code doesn't seem to work:

this.UserInterfaceThread.Abort();

Any ideas? Would Thread.Interrupt() be of any use?

Update

As Hans Passant pointed out:

The CLR imposes rather sane rules on the state of a thread when it aborts it. The perils of Thread.Abort() are well known, what certainly cannot ever work reliably is aborting a thread that's executing unmanaged code. Which is the case when you call Console.ReadLine(), the thread is buried deep inside Windows operating system code.

The solution is to simply poke the [enter] keystroke into the currently running console app, which unblocks Console.ReadLine(), so the thread immediately aborts.

We cannot use SendKeys as this is specific to windows forms, and it also requires the current window to have the focus.

The solution is to use the library at inputsimulator.codeplex.com which wraps the Windows SendInput() call.

See sample code:

.NET call to send [enter] keystroke into the current process, which is a console app?

Community
  • 1
  • 1
Contango
  • 76,540
  • 58
  • 260
  • 305
  • 3
    `Thread.Abort` [is evil](http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation). – spender Jan 24 '12 at 10:04
  • @Darin Dimitrov: Its not a duplicate. This question deals with how to abort a thread that is running a single instance of Console.ReadLine(). – Contango Jan 24 '12 at 10:08
  • @Spender. Yes, in most cases - but how can you even attempt to gracefully close a thread that is running Console.ReadLine()??? – Contango Jan 24 '12 at 10:09
  • 1
    http://stackoverflow.com/questions/9479573/interrupt-console-readline/9479797#9479797 – Hans Passant Feb 28 '12 at 09:57
  • @HansPassant there's now a really nice update as the original solution stopped working on Win10 - https://stackoverflow.com/a/58475263/717732 - unfortunatelly, handles and all probably will work only on Windows and not on other platforms – quetzalcoatl Dec 09 '19 at 13:07

3 Answers3

6

The CLR imposes rather sane rules on the state of a thread when it aborts it. The perils of Thread.Abort() are well known, what certainly cannot ever work reliably is aborting a thread that's executing unmanaged code. Which is the case when you call Console.ReadLine(), the thread is buried deep inside Windows operating system code.

You are going to have to do this differently. One immediately obvious approach is that you let this 'user interface' thread stop the program instead of the other way around. Could be as simple as a "quit" command or the proverbial "Press any key to continue" message.

Or set the thread's IsBackground property to true. Now you don't have to abort it, Windows will terminate it when it shuts down the process after your Main() method exits.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks for explaining whats going on here. I have another idea: how about poking the [enter] key into the console app, forcing the thread to wake up and abort? There is a method to do this: System.Windows.Forms.SendKeys.SendWait() – Contango Jan 26 '12 at 09:21
  • That's too ugly, SendKeys() is very unreliable. You can get Console.ReadLine() to return by [closing the console input handle](http://stackoverflow.com/a/9479797/17034) – Hans Passant Aug 07 '13 at 16:07
4

Use SendKeys and simulate ENTER key. Get help here.

Good luck.

lsalamon
  • 7,998
  • 6
  • 50
  • 63
  • 1
    Thanks for the tip. I'm using a Console app, so SendKeys may not work - I'm looking into it now. – Contango Jan 26 '12 at 09:34
  • Just found http://inputsimulator.codeplex.com/ apparently it can simulate keystrokes in Console apps. – Contango Jan 26 '12 at 09:36
  • Ended up using http://inputsimulator.codeplex.com/. See the full answer here: http://stackoverflow.com/questions/9016087/net-call-to-send-enter-keystroke-into-the-current-process-which-is-a-console – Contango Jan 26 '12 at 09:50
  • SendKeys has one other major disadvantage: the app has to have the current focus. This rules it out for any app that might be running in the background. – Contango Jan 26 '12 at 10:07
2

I've just tested it, neither Thread.Abort() nor Thread.Interrupt() work on a thread that is calling to Console.ReadLine(), even when calling it through a StreamReader( new BufferedStream(...)).

I even tried calling Console.In.Close() and Dispose(). It seems once you're in a read, you're really in there; strange because that seems to break the design of streams.

It really looks like your only option is to use the answer mentioned by @Darin-Dimitrov

Edit: Knocked another one off the list: Tried calling the win32 api FreeConsole. Causes a memory corruption exception from the Console.ReadLine() call.

antiduh
  • 11,853
  • 4
  • 43
  • 66
  • I have another idea: how about poking the [enter] key into the console app, forcing the thread to wake up and abort? There is a method to do this: System.Windows.Forms.SendKeys.SendWait() – Contango Jan 26 '12 at 09:20