在控制台窗口应用程序中通过用户输入暂停当前线程

时间:2012-01-22 18:09:36

标签: c# multithreading input console

这是我想出的用于在控制台内暂停/恢复活动线程的解决方案......

它需要第二个线程用于输入,主循环也会做出反应。但是我对C#的无知让我想知道是否有更简单的解决方案?也许可以单独使用主线程完成一个?

基本上,我正在测试几个会在定义的FPS上迭代的东西,我希望能够通过键盘输入暂停和恢复迭代。任何反馈都表示赞赏。

class TestLoops
{
    int targetMainFPS = 5;
    int targetInputFPS = 3;
    bool CONTINUE = true;

    Thread testLoop, testLoop2;
    ConsoleKeyInfo cki;

    ManualResetEvent resetThread = new ManualResetEvent(true); //How to correctly pause threads in C#.
        public void Resume() { resetThread.Set(); }
        public void Pause() { resetThread.Reset(); }

    public TestLoops()
    {
        //_start = DateTime.Now.Ticks;
        Console.Write("CreatingLoop...");

        this.testLoop = new Thread(MainLoop);
        this.testLoop.Start();

        this.testLoop2 = new Thread(InputLoop);
        this.testLoop2.Start();
    }

    void MainLoop()
    {
        long _current = 0;
        long _last = 0;

        Console.Write("MainLoopStarted ");
        while(CONTINUE)
        {
            resetThread.WaitOne();

            _current = DateTime.Now.Ticks / 1000;
            if(_current > _last + (1000 / targetMainFPS) )
            {
                _last = _current;

                //Do something...
                Console.Write(".");

            }
            else
            {
                System.Threading.Thread.Sleep(10);
            }
        }
    }

    void InputLoop()
    {
        long _current = 0;
        long _last = 0;

        Console.Write("InputLoopStarted ");
        while(CONTINUE)
        {
            _current = DateTime.Now.Ticks / 1000;
            if(_current > _last + (1000 / targetInputFPS))
            {
                _last = _current;

                //Manage keyboard Input
                this.cki = Console.ReadKey(true);
                //Console.Write(":");
                if(this.cki.Key == ConsoleKey.Q)
                {
                    //MessageBox.Show("'Q' was pressed.");
                    CONTINUE = false;
                }

                if(this.cki.Key == ConsoleKey.P)
                {
                    this.Pause();
                }
                if(this.cki.Key == ConsoleKey.R)
                {
                    this.Resume();
                }
            }
            else
            {
                System.Threading.Thread.Sleep(10);
            }
        }
    }

    public static void Main(string[] args)
    {
        TestLoops test = new TestLoops();
    }

}

2 个答案:

答案 0 :(得分:3)

您可以使用非阻止Console.KeyAvailable检查来大幅简化它。这样,您就可以从主线程执行所有代码:

using System;
using System.Threading;

class TestLoops
{
    const int targetFPS = 5;

    public static void Main(string[] args)
    {
        bool _continue = true;
        DateTime _last = DateTime.MinValue;

        while (_continue)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo cki = Console.ReadKey(true);

                if (cki.Key == ConsoleKey.Q)
                {
                    Console.WriteLine("\n'Q' was pressed.");
                    _continue = false;
                }

                if (cki.Key == ConsoleKey.P)
                {
                    Console.WriteLine("\n'P' was pressed; press 'R' to resume.");

                    // Block until 'R' is pressed.
                    while (Console.ReadKey(true).Key != ConsoleKey.R)
                        ; // Do nothing.

                    Console.WriteLine("'R' was pressed.");
                }
            }

            DateTime _current = DateTime.Now;
            if (_current - _last > TimeSpan.FromMilliseconds(1000F / targetFPS))
            {
                _last = _current;

                // Do something...
                Console.Write(".");
            }
            else
            {
                System.Threading.Thread.Sleep(10);
            }
        }        
    }
}

修改:回复评论。

小心点。由于Console.ReadKey调用,下面的代码会阻止,而不是while循环。 while循环只有这样,如果用户输入R以外的字符,程序将丢弃它并等待输入另一个字符。

// Block until 'R' is pressed.
while (Console.ReadKey(true).Key != ConsoleKey.R)
    ; // Do nothing.

如果您想要阻止按下任何字符,您只需使用:

Console.ReadKey(true);

答案 1 :(得分:0)

这样可行,是的。您可以考虑的唯一事情就是确保工作线程在您按下Q键时,即使先前已暂停,也会停止:

if(this.cki.Key == ConsoleKey.Q)
{
     CONTINUE = false;
     this.Resume(); // <-- make sure that the worker thread resumes
}

作为旁注,常量FPS通常由跳过帧维护,而不是暂停线程。暂停线程是不精确的,并且不允许微调动画速度。 Thread.Sleep在不同硬件上的行为也可能不同,并且分辨率可能相当差(最小OS时间片约为16ms IIRC)。

相关问题