为什么第二个 UI 线程会冻结第一个? [英] Why a second UI thread freezes the first one?

查看:50
本文介绍了为什么第二个 UI 线程会冻结第一个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含两个 UI 线程和一个后台工作线程的应用程序.一切正常,除了在第二个模拟 UI 线程中处理 ProgressChanged 会阻塞第一个.为什么会发生?我该如何解决此问题(我希望阻止第二个线程而不是主 UI 线程)?

I've got an application with two UI threads and one background worker. Everything works fine except that handling ProgressChanged in the second simulation UI thread blocks the first one. Why it happens? How can I workaround this (I want the second one be blocked instead of the main UI thread)?

MainWindow 类的一部分:

Part of MainWindow class:

private SimulationWindow simulationWindow;

    public MainWindow()
    {
        InitializeComponent();
        Thread thread = new Thread(() =>
        {
            simulationWindow = new SimulationWindow();
            simulationWindow.Show();
            simulationWindow.Closed += (sender2, e2) =>
                      simulationWindow.Dispatcher.InvokeShutdown();
            Dispatcher.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    private void start_Click(object sender, RoutedEventArgs e)
    {
        simulationWindow.Start();
    }

SimulationWindow 类的一部分:

Part of SimulationWindow class:

private BackgroundWorker bw;

public SimulationWindow()
{
    InitializeComponent();
    bw = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    //some complex computation will go here
    //Thread.Sleep(10000); <- both windows responsive, OK
    bw.ReportProgress(0);
}


void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //some complex rendering will go here
    Thread.Sleep(10000); // this blocks main UI thread, why?
}

public void Start()
{
    bw.RunWorkerAsync();
}

private void doSth_Click(object sender, RoutedEventArgs e)
{
    Thread.Sleep(10000); // freezes simulationWindow, which was understandable
}

推荐答案

您在主 UI 线程上调用 simulationWindow.Start().这意味着 BW 在该线程上启动,这意味着它捕获主 UI 线程的 SynchronizationContext,因此也在该线程上引发 ProgressChanged.

You call simulationWindow.Start() on the main UI thread. This means the BW is started on that thread, which means it captures the SynchronizationContext of the main UI thread and so also raises ProgressChanged on that thread.

您需要将对 bw.RunWorkerAsync() 的调用编组到您的第二个线程.您可以在 SimulationWindow.Start() 中通过调用 this.Dispatcher.Invoke 并传递 bw.RunWorkerAsync() 作为委托来执行此操作.然后它应该在您的第二个窗口线程上运行,并且事件将在该线程上引发.

You need to marshal the call to bw.RunWorkerAsync() on to your second thread. You can do this in SimulationWindow.Start() by calling this.Dispatcher.Invoke and passing bw.RunWorkerAsync() as the delegate. It should then run on your second window thread and the events will be raised on that thread.

这篇关于为什么第二个 UI 线程会冻结第一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆