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!");
}
}
...
运行程序后,它总是被冻结。 我搜索了我的问题,我发现这是因为死锁问题。 我该如何解决这个问题?
答案 0 :(得分:1)
你是对的,这是一个死锁问题。
Parallel.ForEach
阻止list
中的所有项目都已处理,并且您在UI线程上运行,所以现在UI线程被阻止。
然后您调用Form1.setText(test + "done!");
和setText
(s
确实应该是资本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
。