平行冻结我的表格

时间:2013-11-16 04:29:59

标签: c# multithreading textbox parallel-processing deadlock

Form1.cs

...
delegate void SetTextCallback(string text);
...

public void setText(string s)
{
    if (this.textbox1.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(setText);
        this.Invoke(d, new object[] { s });
    }
    else
    {
        textbox1.AppendText(s + Environment.NewLine);
        Application.DoEvents();
    }
}
...
private void btn_Click(object sender, eventArgs e)
{
     Test t = new Test();
     t.run();
}

和Test.cs

...
public void run()
{
    Parallel.ForEach(list, test =>
    {
        DoSomething(test);
        Form1.setText(test + "done!");
    }
}
...

运行程序后,它总是被冻结。 我搜索了我的问题,我发现这是因为死锁问题。 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

你是对的,这是一个死锁问题。

Parallel.ForEach阻止list中的所有项目都已处理,并且您在UI线程上运行,所以现在UI线程被阻止。

然后您调用Form1.setText(test + "done!");setTexts确实应该是资本btw)调用this.Invoke,这将阻止调用调用完成处理。但是,因为我们阻止了Parallel.ForEach上的UI线程,所以它永远不会被处理而你刚刚陷入僵局!

解决这个问题的方法是将Parallel.ForEach调用放在它自己的线程上,这样就不会阻塞UI线程。

public void run()
{
    Task.Factory.StartNew(() => Parallel.ForEach(list, test =>
    {
        DoSomething(test);
        Form1.setText(test + "done!");
    }), TaskCreationOptions.LongRunning);
}

您还可以通过将this.Invoke更改为this.BeginInvoke 1 来提高效果,因此文本更新也是非阻止性的。但是,如果您只对程序进行BeginInvoke更改并将Parallel.ForEach保留在UI线程中,则可能不再死锁,但您的用户界面仍然会冻结并说Not Responding直到Parallel.ForEach完成。


1。在其他任何地方,如果您致电BeginXxxxx 必须 致电EndXxxxx,而BeginInvoke来自Control { {3}}并且您无需致电EndInvoke