Pump message in console application

I have a fairly simple console application written in .NET. Sometimes an application is launched in batch mode without an operator; in other cases, it is launched "out of pocket". If it works in batch mode, there is a specific default setting that allows the program to start automatically. If an operator is present, there are other options that allow the user to select from a list of functions.

For reasons I don't want to go into, command line options are not preferred. Instead, I created a 10 second window in which the operator can select a function. I am currently using a simple while loop and reading input from the "in" stream. I added Thread.Sleep at the end to prevent a full processor cycle, but I would like to know if there is a better way.

A Windows application ( Windows Forms or WPF ) has a message pump that can read the message queue and then return control to the system. Even heavy-duty applications such as Visual Studio, SAS User Guide, and SQL Server Studio Management use almost 0% of the processor when they are idle. Can I get the same effect from my console application?

Thread.Sleep works, but, as I said, I want to know if there is a better way.

Here is the source code:

class Program { static void Main( string[] args ) { DateTime l_startTime = DateTime.Now; Console.CursorVisible = false; Console.WriteLine( "Please select an option within 10 seconds..." ); Console.WriteLine( "" ); Console.WriteLine( " [1] Option A (DEFAULT)" ); Console.WriteLine( " [2] Option 2" ); Console.WriteLine( " [3] Option III" ); int l_elapsedSeconds = 0; bool l_exit = false; while ( !l_exit ) { int l_currentElapsedSeconds = (int) Math.Floor( ( DateTime.Now - l_startTime ).TotalSeconds ); if ( l_currentElapsedSeconds > l_elapsedSeconds ) { Console.CursorTop = 0; Console.CursorLeft = 0; l_elapsedSeconds = l_currentElapsedSeconds; int l_remainingSeconds = 10 - l_elapsedSeconds; Console.WriteLine( String.Format( "{0,-80}", "Please select an option within " + l_remainingSeconds + " seconds..." ) ); } if ( l_elapsedSeconds >= 10 ) { OptionA(); break; } if ( Console.KeyAvailable ) { var l_key = Console.ReadKey( true ); switch ( l_key.Key ) { case ConsoleKey.D1: OptionA(); l_exit = true; break; case ConsoleKey.D2: Option2(); l_exit = true; break; case ConsoleKey.D3: OptionIII(); l_exit = true; break; } } if ( !l_exit ) // Don't eat all the processor System.Threading.Thread.Sleep( 100); } Console.CursorTop = 7; Console.CursorLeft = 0; Console.Write( "Press any key to continue..."); Console.ReadKey( true); } static void OptionA() { Console.CursorTop = 6; Console.CursorLeft = 0; Console.WriteLine( "Option A Selected!"); } static void Option2() { Console.CursorTop = 6; Console.CursorLeft = 0; Console.WriteLine( "Option 2 Selected!"); } static void OptionIII() { Console.CursorTop = 6; Console.CursorLeft = 0; Console.WriteLine( "Option III Selected!"); } } 

Note. This question does not concern the timeout ... it is about using 0% of processor time while waiting for an answer (for example, a window application).

+7
source share
2 answers

You can start a stream that reads keystrokes in the background. Add the keys to the lock queue and wait in the main thread to fill the queue, for example.

 var queue = new BlockingCollection<ConsoleKeyInfo>(); new Thread(() => { while (true) queue.Add(Console.ReadKey(true)); }) { IsBackground = true }.Start(); Console.Write("Welcome! Please press a key: "); ConsoleKeyInfo cki; if (queue.TryTake(out cki, TimeSpan.FromSeconds(10))) //wait for up to 10 seconds { Console.WriteLine(); Console.WriteLine("You pressed '{0}'", cki.Key); } else { Console.WriteLine(); Console.WriteLine("You did not press a key"); } 

Both the background thread and the main thread will sleep (using 0% of CPU time) while they expect ReadKey and TryTake to return, respectively.

+8
source

You can use the .NET event processing engine. Cancel here .

 Imports System.Threading.Thread Module Module1 Private Second As Integer = 1 Private Tick As New Timers.Timer(1000) Sub Main() AddHandler tick.Elapsed, AddressOf Ticker 'Event for the timer tick Dim NewThread As System.Threading.Thread = New System.Threading.Thread(AddressOf LookForKeyPress) 'New thread to check for key press NewThread.Start() 'Start thread Console.WriteLine("Now awaiting key presses...") tick.Enabled = True 'Enable the timer End Sub Private Sub Ticker() 'every tick this sub is called and the seconds are displayed till a key is pressed Console.WriteLine(Second) Second += 1 End Sub Private Sub LookForKeyPress() While True Dim k As ConsoleKeyInfo = Console.ReadKey() 'read for a key press If Not k.Key.ToString.Length <= 0 Then 'check the length of the key string pressed, mainly because the key in this case will be apart of the system.consolekey Console.WriteLine(Environment.NewLine & "Key Pressed: " & k.Key.ToString) 'display the key pressed Second = 1 'restart the timer End If End While End Sub End Module 

I hope I helped!

0
source

All Articles