当我尝试从另一个线程更新UI时,应用程序没有响应

时间:2015-01-02 12:03:44

标签: c# multithreading thread-safety invoke autoresetevent

执行流程:

  1. 从主线程我调用了新线程(并行线程),这是一个长时间运行的过程。
  2. 并行线程正在更新主线程UI。
  3. 我让我的主线程等到并行线程完成。
  4. 我需要两个线程之间的同步。
  5. 我需要在主线程中使用并行线程的结果,所以我阻塞了主线程,直到并行进程完成。
  6. 这是我的代码有问题, 请提出解决问题的建议。

        private readonly AutoResetEvent _resetEvent = new AutoResetEvent(false);
        private event EventHandler Workcompleted;
    
        private void button1_Click(object sender, EventArgs e)
        {
            Workcompleted += Completed;
            Thread thr = new Thread(UpdateUI);
            thr.Start("");
    
            _resetEvent.WaitOne();
    
             // Logical operation dependent on parallel process final result 
    
        }
    
        private void Completed(object sender, EventArgs args)
        {
            _resetEvent.Set();
        }
    
        private void UpdateUI(object txt)
        {
            for (int i = 0; i < 10; i++)
            {
                if (label1.InvokeRequired)
                {
                    label1.Invoke(new ParameterizedThreadStart(UpdateUI), i.ToString());
                }
                else
                {
                    label1.Text = (string)txt;
                    Thread.Sleep(100);
                }
            }
    
            if (Workcompleted != null)
                Workcompleted(this, new EventArgs());
    
        }
    

3 个答案:

答案 0 :(得分:3)

  

我让我的主线程等到并行线程完成。

你在那里封锁了自己。你为什么一开始就开始一个新线程?保持UI响应。现在你无论如何阻止了它。 不要阻止它。我不知道在线程运行时你想做什么,可能会改变控制状态并在线程完成后重置它们,但你不要想要阻止你的UI线程。停下来,找到另一种方法来实现你想要达到的目标。

答案 1 :(得分:0)

 public delegate void Action();
    private void UpdateUI(object txt)
    {
        this.BeginInvoke((Action)(() =>
        {
            label2.Text = (string)txt;
        })); 
    }

通过使用此代码,我们不需要等待另一个线程...

答案 2 :(得分:0)

您似乎正在寻找一种在并行操作过程中报告UI进度的方法,并等待最终结果(同步)对其进行操作。

这可以使用Async/Await轻松完成,无需运行手动线程,同步构造或线程编组(用于UI调用),最重要的是不会阻止UI线程。

以下是如何运行并行操作,将进度报告回UI,连续更新UI以及最终在结果可用时执行某些操作的示例。

private async void button1_Click(object sender, EventArgs e)
{
    var progress = new Progress<int>(ShowProgressInUi);
    var result = await Task.Run(() => DoParallelWorkAsync(progress));

    // Do something with final result
    label1.Text = result;
}

private void ShowProgressInUi(int progress)
{
    label1.Text = string.Format("Progress: {0} % done...", progress);
}

private static async Task<string> DoParallelWorkAsync(IProgress<int> progress)
{
    // This work is done in a separate thread.
    // In this case a background thread (from the thread pool),
    // but could be run on a foreground thread if the work is lengthy.
    for (var i = 1; i <= 10; i++)
    {
        // Simulate workload
        await Task.Delay(100);
        progress.Report(i * 10);
    }

    return "All done";
}