9

.NETで記述された非常に単純なコンソールアプリケーションがあります。アプリケーションがオペレーターなしでバッチモードで実行される場合もあれば、「ポケットから」実行される場合もあります。バッチモードで実行している場合は、プログラムを自動的に実行できるようにするデフォルトのオプションが定義されています。オペレーターが存在する場合、ユーザーが機能のリストから選択できるようにする他のオプションがあります。

入りたくない理由で、コマンドラインパラメータは好ましくありません。代わりに、オペレーターが関数を選択できる10秒のウィンドウを作成しました。現在、単純なwhileループを使用して、「in」ストリームから入力を読み取っています。whileループがプロセッサを完全に消費しないように、最後にThread.Sleep呼び出しを追加しましたが、もっと良い方法があるかどうか知りたいです。

Windowsアプリケーション(WindowsフォームまたはWPF)には、メッセージのキューを読み取ってシステムに制御を戻すことができるメッセージポンプがあります。Visual Studio、 SAS Enterprise GuideSQL 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%のプロセッサー時間を使用することについてです(ウィンドウ化されたアプリケーションのように)。

4

2 に答える 2

10

バックグラウンドでキーの押下を読み取るスレッドを開始できます。ブロッキングキューにキーを追加し、メインスレッドでキューがいっぱいになるのを待ちます。

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%のプロセッサ時間を利用します)。

于 2012-08-31T20:03:56.580 に答える
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

私が助けてくれたことを願っています!

于 2013-12-22T10:46:36.047 に答える