[英]Message pump in a console application
我有一个用.NET编写的相当简单的控制台应用程序。 有时应用程序在没有操作员的情况下以批处理模式运行,有时它是“自掏腰包”运行的。 如果它以批处理模式运行,则会有一个定义的默认选项,允许程序自动运行。 如果存在操作员,则还有其他选项允许用户从功能列表中进行选择。
由于我不想进入的原因,命令行参数不是首选。 相反,我创建了一个10秒的窗口,操作员可以在其中选择一个功能。 目前,我正在使用一个简单的while循环并从“in”流中读取输入。 我在最后添加了一个Thread.Sleep调用,以防止while循环完全消耗处理器,但我想知道是否有更好的方法。
在Windows应用程序( Windows窗体或WPF )中,有一个消息泵,它能够读取消息队列,然后将控制权返回给系统。 即使像Visual Studio, SAS Enterprise Guide和SQL Server Management Studio这样的重型应用程序在空闲时也几乎使用了0%的处理器。 我的控制台应用程序可以获得相同的效果吗?
Thread.Sleep正在工作,但正如我所说,我想知道是否有更好的方法。
这是源代码:
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!");
}
}
注意:这个问题并不关心超时......它是关于在等待响应时使用0%处理器时间(如窗口化应用程序)。
您可以启动一个在后台读取按键的线程。 将密钥添加到阻塞队列并在主线程中等待队列填充,例如
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");
}
后台线程和主线程都将在等待ReadKey和TryTake分别返回时休眠(利用0%处理器时间)。
您可以使用.NET的事件处理机制。 从这里转发。
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
希望我帮忙!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.