【问题标题】:Creating infinite loop without breaking program在不破坏程序的情况下创建无限循环
【发布时间】:2014-03-08 19:13:46
【问题描述】:

我有一个按“步骤”更新的游戏网格(康威的人生游戏,尽管这与我的问题无关)。我正在尝试创建一个自动运行模拟的播放按钮,直到再次按下该按钮以暂停模拟。起初我有这样的事情:

public partial class MainWindow : Window
{
    bool running = true;
    public MainWindow()
    {   
        InitializeComponent();
        bool isProgramRunning = true;
        while(isProgramRunning)
        {
            while(running)
            ProcessGeneration();
        }
    }
}

我播放/暂停模拟的按钮具有以下点击处理程序:

private void PlayClick_Handler(object sender, RoutedEventArgs e)
{           
     PlayButton.Content = ((string)PlayButton.Content == "Play") ? "Pause" : "Play";

     running = (running) ? false : true;
}

我认为这会让我的程序简单地保持循环(isProgramRunning 永远不会结束)反复检查“正在运行”是真还是假,并且按下按钮切换“正在运行”将允许我循环/跳出环形。但是只是 while(isProgramRunning) 部分会杀死程序(它甚至不会加载)。实际上,每次我尝试使用 while() 时,程序都会停止响应。有没有办法解决这个问题?

【问题讨论】:

  • 一句忠告:通过实施 Gosper 的生命算法,你可以很多学习函数式编程;它允许您支持非常大的电路板和非常快速的计算——具有数万亿个单元和每秒数万亿代的电路板——所有这些都使用完全普通的硬件。
  • 您可以在 UI 线程上运行 background asynchronous operation,以避免阻塞 WPF Dispatcher 循环。

标签: c# wpf loops while-loop


【解决方案1】:

您可能不希望您的ProcessGeneration() 尽快发生,屏幕上的所有内容都会变得模糊。此外,您不想阻塞 UI 线程。一块石头可以杀死两只鸟,Timer

创建一个计时器,让它每 1/4 秒运行一次,或者您希望它更新的频率。然后在您的开始和停止代码中,您只需要启用或禁用计时器。

public partial class MainWindow : Window
{
    private readonly System.Timers.Timer _timer;

    public MainWindow()
    {   
        InitializeComponent();

        _timer = new Timer(250); //Updates every quarter second.
        _timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
    }

    private void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        ProcessGeneration();
    }

    private void PlayClick_Handler(object sender, RoutedEventArgs e)
    {           
         var enabled = _timer.Enabled;
         if(enabled)
         {
             PlayButton.Content = "Play";
             _timer.Enabled = false;
         }
         else
         {
             PlayButton.Content = "Pause";
             _timer.Enabled = true;
         }
    }

}

【讨论】:

    【解决方案2】:

    Scott Chamberlain 的建议是正确的。我要补充一点,它有助于理解您的程序停止响应的原因。这是因为那里还有另一个你看不到的无限循环。它看起来像这样:

    while(true)
    {
        get the next notification from the operating system
        if its a quit message, exit
        otherwise, run the event handler associated with the message
    }
    

    这个循环得到一条消息说“程序正在启动”,所以它运行你的构造函数,然后它会永远在一个循环中。它永远不会返回到消息循环,因此鼠标单击消息永远不会从队列中获取,也不会被处理,因此您的循环不会停止。

    计时器是个好主意。您还可以使用其他技术。我不建议创建工作线程;多线程在您的程序中引入了大量的复杂性。我也建议不要使用DoEvents;它以递归方式启动 second 消息循环,这可能会引入重入错误。我确实建议在 C# 5 中使用 await,尽管它可能有点难以理解。

    【讨论】:

    • Eric,this 之类的内容是否与您对await 的建议相近?
    • @Noseratio:是这样的。
    【解决方案3】:

    要不停止程序的主线程运行,请为ProcessGeneration 方法添加一个单独的线程。单击按钮时,停止该线程。此外,这实际上取决于您正在运行的进程。如果它们不连续,请按照@ScottChamberlain 所说的那样使用计时器。但是,如果您需要始终执行某个操作,请为其使用单独的线程,这样它就不会阻塞您的主线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 2018-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多