【问题标题】:Running Code After Infinite While Loop在无限 While 循环后运行代码
【发布时间】:2014-01-30 05:36:33
【问题描述】:

我正在尝试制作一个控制台应用程序。我想要 ”。 。 。”在“按任意键退出”后闪烁。

闪烁工作正常,但现在我的 Console.ReadKey() 是无法访问的代码。
我只是想知道是否有任何方法可以到达 Console.ReadKey() 行,或者我会将它移动到哪里才能让它运行?

static void Main(string[] args)
    {
        string blinkExit = ". . .";           //Variable for blinking periods after 'exit'

        Console.Write("\n\nPress any key to exit");              //Displays a message to press any key to exit in the console

        while (true)
        {
            WriteBlinkingText(blinkExit, 500, true);
            WriteBlinkingText(blinkExit, 500, false);
        }

        Console.ReadKey();

    }

private static void WriteBlinkingText(string text, int delay, bool visible)
    {
        if (visible)
            Console.Write(text);
        else
            for (int i = 0; i < text.Length; i++)
                Console.Write(" ");
            Console.CursorLeft -= text.Length;
            System.Threading.Thread.Sleep(delay);
    }

【问题讨论】:

  • 如果你需要同时做两件事,试试线程。或者,您可以在循环中检查键盘状态...
  • 我应该补充一下,我对 C# 很陌生;这实际上是我的第一个学期。我将研究键盘状态,但您会推荐什么作为最简单的解决方案?
  • 啊,这是作业吗?
  • 是的。我们不需要做一个循环,我只是为了额外添加它。我们的赋值实际上只是声明,设置变量然后显示它们。我想做些额外的事情。
  • 我不会给你额外的功劳。

标签: c# while-loop infinite-loop


【解决方案1】:

将线程想象为工作线程,当您使用控制台应用程序时,您正在处理一个线程,并且通过使用不会结束的循环,您实际上是在阻止任何其他任务从该点开始发生,因为线程是忙循环!

要解决这个问题,你需要在循环中放置一个触发器,一旦按下一个键就会退出。我在下面演示了一种简单的方法。

检查代码,你会发现我使用了一个名为Interlocked 的新类,我使用它的原因是为了避免任何线程安全问题,线程安全是一个很深的话题,而不是我想用几句话来解释,但想法是两个不同线程之间共享的任何资源都必须被锁定。您还会发现一个 lambda 表达式,这些都是中间主题,现在尝试学习它们将实现一件事……令人头疼!

    private static long _isKeyPressed;

    private static void Main()
    {
        // Create a new Thread and Start it. 
        new Thread(() =>
        {
            // Variable for blinking periods after 'exit'
            const string blinkExit = ". . .";

            // Displays a message to press any key to exit in the console
            Console.Write("\n\nPress any key to exit"); 

            // Run until no keys are pressed.
            while (Interlocked.Read(ref _isKeyPressed) == 0)
            {
                WriteBlinkingText(blinkExit, 500, true);
                WriteBlinkingText(blinkExit, 500, false);
            }
        }).Start();

        Console.ReadKey();

        // Once a key has been pressed, increment the value of _isKeyPressed to 1.
        // This will indicate to the thread running above that it should exit it's loop.
        // as _isKeyPressed is no longer equal to 0.
        Interlocked.Increment(ref _isKeyPressed);
    }

    private static void WriteBlinkingText(string text, int delay, bool visible)
    {
        if (visible) Console.Write(text);
        else
        {
            for (int i = 0; i < text.Length; i++)
            {
                Console.Write(" ");
            }
        }

        Console.CursorLeft -= text.Length;
        Thread.Sleep(delay);
    }

【讨论】:

  • 这个问题是线程不会终止,因此应用程序不会终止
  • 我很确定这样做会导致程序在按下键后挂起。为此使用 TPL 的正确方法是使用 cancelToken;在while循环中,第一行检查token是否通过,然后退出循环。
【解决方案2】:

只需用这个更改您的 while 代码

        Task.Factory.StartNew(() =>
        {
            while (true)
            {
                WriteBlinkingText(blinkExit, 500, true);
                WriteBlinkingText(blinkExit, 500, false);
            }
        });

按任意键将关闭控制台

【讨论】:

  • 这行得通,谢谢。如果不是太多,我可以问一下第一行是做什么来完成这项工作的吗?
  • 它启动了一个新任务,这是一个托管线程来运行一个新的Action,其语法为() =&gt; { /* code */ }
  • 再次,我是新人。那么任务中的任何内容都与运行的主代码分开运行吗?如,代码运行到整个循环,然后在它自己的“线程”中运行循环,但也会继续并运行 Console.ReadKey()?
  • @WolfieeifloW,我建议你去阅读 MSDN 上的任务是如何工作的。但大部分是的,你是对的
  • 我已经使用了一点 MSDN,但我肯定会更多地研究它。
【解决方案3】:

您似乎只是希望此文本闪烁,直到用户按下某个键。如果是这样,那为什么不直接循环,直到有一个可供读取的密钥?

while (!Console.KeyAvailable)
{
    WriteBlinkingText(blinkExit, 500, true);
    WriteBlinkingText(blinkExit, 500, false);
}

这避免了使用多线程可能出现的所有令人讨厌的问题

【讨论】:

  • 虽然它在实际退出程序之前有一点延迟,但效果非常好!我正在查看 KeyAvailable 函数,显然这是我需要的。
猜你喜欢
  • 2020-05-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
  • 2015-06-25
相关资源
最近更新 更多