当使用并行时,BeginInvoke是工作的,而Invoke不是——c# 4.0

本文关键字:Invoke 不是 工作 并行 BeginInvoke | 更新日期: 2023-09-27 18:10:11

当我在AddListBoxItem函数内使用invoke时,如下所示软件变得无响应和冻结,但如果我使用BeginInvoke它工作。为什么会这样?

visual studio 2010, c# 4.0

 private void button2_Click(object sender, EventArgs e)
{
    var watch = Stopwatch.StartNew();
    Parallel.For(2, 20, (i) =>
    {
        var result = SumRootN(i);
        AddListBoxItem("root " + i + " : " + result);
    });
    AddListBoxItem(watch.ElapsedMilliseconds.ToString());            
}
private delegate void AddListBoxItemDelegate(object item);
private void AddListBoxItem(object item)
{
    if (this.listBox1.InvokeRequired)
    {
        this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item);
    }
    else
    {
        this.listBox1.Items.Add(item);
    }
}

当使用并行时,BeginInvoke是工作的,而Invoke不是——c# 4.0

UI线程将等待Parallel.For完成后再继续。这意味着它不能处理任何进一步的UI消息,直到它完成。

现在,当工作线程调用Invoke,他们等待直到UI线程处理委托之前,他们继续。所以他们在等待UI线程获得自由,基本上。

因此,你有一个死锁——UI线程正在等待任务,任务正在等待UI线程…BeginInvoke工作是因为任务线程等待委托在UI线程中被处理。

我建议你不要在UI线程中调用Parallel.For。你将阻塞UI直到它完成,这不是一个好主意。在后台线程中完成所有的事情-然后你仍然可以使用Invoke,如果你想,当它在做计算时,UI仍然会响应。

听起来像是UI线程死锁。这很有意义,因为button2_ClickFor完成之前不会退出,特别是,在button2_Click完成之前不能处理任何消息循环事件。如果您在不同的线程上,Invoke 使用一个消息循环事件,并且在该项目被处理之前不会返回-因此什么都不会做-并且For/button2_Click将永远不会完成。

通过使用BeginInvoke,您只需队列此工作- BeginInvoke立即返回。这意味着For可以完成,这让button2_Click完成,然后允许处理消息循环事件(更新UI)。

我认为这是因为主线程被阻塞在上面的点击事件,等待完成AddListBoxItem,这是等待butttion2_click事件返回。
你不应该在你的UI中有控制器逻辑,所以Click没有在不同线程中调用逻辑的主要问题。

在为你的逻辑实现一个线程之后,你的GUI不会阻塞,并且在任何情况下都可以轻松刷新。