控制台应用程序中的消息泵 [英] Message pump in a console application

查看:137
本文介绍了控制台应用程序中的消息泵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用.NET编写的相当简单的控制台应用程序。有时,应用程序在没有操作员的情况下以批处理模式运行,而有时它是自费运行的。如果以批处理模式运行,则有一个已定义的默认选项,该选项可使程序自动运行。如果存在操作员,则还有其他选项允许用户从功能列表中进行选择。



由于我不想进入的原因,请使用命令-line参数不是首选。相反,我创建了一个10秒的窗口,操作员可以在其中选择功能。目前,我正在使用一个简单的while循环,并从输入流中读取输入。我添加了最后调用Thread.Sleep 来防止while循环完全消耗处理器,但是我想知道是否有更好的方法。



在Windows应用程序中( Windows窗体 WPF )中存在一个消息泵,它能够读取消息队列,然后将控制权返回给系统。甚至像Visual Studio, SAS企业指南 SQL Server Management Studio 闲置时实际上使用了0%的处理器。我的控制台应用程序可以达到相同的效果吗?



Thread.Sleep可以正常工作,但是正如我所说,我想知道是否有更好的方法。 / p>

以下是源代码:

  class Program {
静态void Main(string [] args){

DateTime l_startTime = DateTime.Now;

Console.CursorVisible = false;
Console.WriteLine(请在10秒内选择一个选项...);
Console.WriteLine();
Console.WriteLine( [1]选项A(默认));
Console.WriteLine( [2]选项2);
Console.WriteLine( [3]选项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},请在 + l_remainingSeconds + second ...)中选择一个选项)
}

如果(l_elapsedSeconds> = 10){
OptionA();
休息时间;
}

if(Console.KeyAvailable){
var l_key = Console.ReadKey(true);

开关(l_key.Key){
case ConsoleKey.D1:
OptionA();
l_exit = true;
休息时间;

情况ConsoleKey.D2:
Option2();
l_exit = true;
休息时间;

情况ConsoleKey.D3:
OptionIII();
l_exit = true;
休息时间;
}
}

if(!l_exit)
//不要吃掉所有处理器
System.Threading.Thread.Sleep(100) ;
}

Console.CursorTop = 7;
Console.CursorLeft = 0;

Console.Write(按任意键继续...);
Console.ReadKey(true);

}

静态无效OptionA(){
Console.CursorTop = 6;
Console.CursorLeft = 0;

Console.WriteLine(选择了选项A!);
}

静态无效Option2(){
Console.CursorTop = 6;
Console.CursorLeft = 0;

Console.WriteLine(选择选项2!);
}

静态无效OptionIII(){
Console.CursorTop = 6;
Console.CursorLeft = 0;

Console.WriteLine(选择选项III!);
}
}

注意:此问题是不关心超时...它是关于等待响应(例如带窗口的应用程序)时使用0%的处理器时间。

解决方案

您可以启动一个线程,该线程在后台读取按键。将密钥添加到阻塞队列中,并在主线程中等待队列被填充,例如

  var queue = new BlockingCollection< ; ConsoleKeyInfo>(); 

new Thread(()=>
{
while(true)queue.Add(Console.ReadKey(true));
})
{IsBackground = true} .Start();


Console.Write(欢迎!请按一个键:);

ConsoleKeyInfo cki;

if(queue.TryTake(out cki,TimeSpan.FromSeconds(10)))//等待最多10秒钟
{
Console.WriteLine();
Console.WriteLine(您按下了 {0},cki.Key);
}
else
{
Console.WriteLine();
Console.WriteLine(您没有按任何键);
}

后台线程和主线程都将休眠(利用0%的处理器时间),而他们分别等待ReadKey和TryTake返回。


I have a fairly simple console application written in .NET. Sometimes the application is run in batch mode without an operator, other times it is run "out of pocket". If it's running in batch mode, there is a defined default option which allows the program to run automatically. If there is an operator present, there are other options which allow the user to select from a list of functions.

For reasons I don't want to go into, command-line parameters are not preferred. Instead, I've created a 10-second window in which an operator may choose a function. Currently, I'm using a simple while loop and reading input from the "in" stream. I've added a Thread.Sleep call at the end to prevent the while loop from completely consuming the processor, but I'd like to know if there's a better way.

In a Windows application (Windows Forms or WPF) there is a message pump which is able to read the queue of messages and then return control to the system. Even heavy-duty applications like Visual Studio, SAS Enterprise Guide and SQL Server Management Studio use practically 0% of the processor when they are idle. Can I get the same effect with my console application?

The Thread.Sleep is working, but, as I said, I want to know if there's a better way.

Here's 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 is not concerned about a timeout... it is about using 0% processor time while waiting for a response (like a windowed application).

解决方案

You could start a thread that reads key presses in the background. Add the keys to a blocking queue and wait in the main thread for the queue to be filled, e.g.

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 (utilize 0% processor time) while they're waiting for ReadKey and TryTake to return respectively.

这篇关于控制台应用程序中的消息泵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆