【问题标题】:Starting and stopping a secondary non-UI thread启动和停止辅助非 UI 线程
【发布时间】:2015-08-26 20:02:19
【问题描述】:

我正在 WPF 中重建我的一个 WinForms 应用程序,但遇到了线程问题。我从 UI 类中的方法启动线程,例如单击按钮:

workerThread = new Thread(() => Engine.Start());
workerThread.Start();

workerThread 方法遵循这种通用格式:

static class Engine 
{
    public static bool RunThread = true;
    public static void Start()
    {
        while (RunThread)
        {
            // Do Stuff
        }
    }
}

这是一个不断向 USB 设备输出数据的循环。当我从程序的其他地方将我的 RunThread 变量更改为 false 时,我只希望这个线程结束。问题在于等待线程完成。如果我关闭我的 MainWindow,线程将继续运行,直到它尝试启动一个新循环然后退出,这意味着它可能会调用 MainWindow 的某些部分,因为它被销毁后不再存在。如果我运行 workerThread.Join();整个应用程序冻结并变得完全没有响应。

以前,我在我的 FormClosing 方法中设置了类似的东西,以确保它会等待线程退出,然后再进行其他清理操作:

if (workerThread != null) {
    // Ask the thread to destroy itself
    Engine.RunThread = false;

    // If the thread is busy, wait for it to end
    while (workerThread.IsAlive)
    {
        Application.DoEvents();
        Thread.Sleep(100);
    }
};

这不是最优雅的,但在 WinForms 中它确保线程干净地退出然后继续。然而,在 WPF 中尝试这样的事情只会导致它卡在 while 循环中;因为我认为它阻止了线程继续并自行关闭。当然,我必须删除 Application.DoEvents(); 因为它在 WPF 中不存在。

我怀疑我没有使用 WPF 中可用的最佳技术创建此线程,所以我的问题是:启动此线程的最佳方法是什么,以便我可以安全地退出它(并可能启动一个新实例) 稍后?

【问题讨论】:

  • 我建议你使用任务而不是线程
  • 你的怀疑是错误的。你需要的是一个后台线程。我投票决定将此问题作为重复问题结束。
  • 我在这个网站上找不到任何东西告诉我如何运行这样的线程。如果这是重复的,它是什么?
  • @Elestriel 查看链接的答案。 workerThread.IsBackground = true; 就是您所需要的。就这么简单。
  • 这可能是一个设计问题:为什么要允许工作线程直接访问UI?工作线程应该通知控制器,控制器应该决定做什么。如果 UI 启动并运行,控制器将通知视图更新。如果 UI 关闭,它只会丢弃新到达的 USB 数据。

标签: c# wpf multithreading


【解决方案1】:

正如 cmets 中的其他人所指出的,使用 Task 而不是 Thread

Task workerTask = Task.Run(() => Engine.Start());

要让 UI 等待关闭直到 Task 完成执行,请处理 WindowClosing 事件并等待 workerTask 完成。

private async void NavigationWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    await workerTask;
}

【讨论】:

  • 我实际上遇到了这个方法的一个新问题。看到新任务是一个无限循环(至少在我告诉它结束之前)它完全冻结了 UI 线程。如果我在任务中使用Thread.Sleep(),它会让 UI 更新,但这并不是一个理想的解决方案。你知道我能做些什么来解决这个问题吗?
  • 它不应该冻结 UI 线程,因为它是一个新线程。您是否以阻塞方式从 UI 线程与任务进行通信?
  • 一旦线程运行,线程和 UI 之间就没有通信,除了我在我的 OP 中提到的 RunThread 变量。老实说,这有点令人困惑。我试过以TaskBackgroundWorkerThread 运行它,使用isBackground = truefalse,它们都被阻塞了。
  • 这不应该是这样,也许设置中的其他东西有问题。为它创建一个新问题,这样您就可以更好地展示您的代码,然后更容易为您提供帮助。
  • 谢谢,但我会尝试自己解决问题。经过数小时尝试不同的事情后,我的 OP 有点绝望!我想通了我在 cmets 中提到的问题;它与更新主窗口上某些按钮的颜色有关。我必须想出一个更好的方法来做到这一点!再次感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多