我想实现的结果很简单,就是用并行的方式去为2个控件赋值,但是结果是窗体会假死,看起来是死锁的样子,不懂为什么,谁能给讲解讲解一下。
代码:
private void button4_Click(object sender, EventArgs e)
{
Parallel.Invoke(
SetLable1Text,
SetLable2Text
);
}
void SetLable1Text()
{
label1.Invoke(new Action(() => {
label1.Text = "正在执行...";
Thread.Sleep(TimeSpan.FromSeconds(3));
label1.Text = "执行完毕";
}));
}
void SetLable2Text()
{
label2.Invoke(new Action(() =>
{
label2.Text = "正在执行...";
Thread.Sleep(TimeSpan.FromSeconds(2));
label2.Text = "执行完毕";
}));
}
Thread.Sleep()阻塞了GUI线程,所以窗体假死了。
你 Parallel.Invoke 在主线程中调用的,要等到invoke参数里所有任务执行完成后 主线程才返回。经过测试,invoke参数里面的第一个任务始终是在主线程中执行的,所以修改UI能成功,而后面的任务在其他线程执行。当第二个任务开始的时候,在调用label2.Invoke的时候 是子线程请求主线程更新UI,但是主线程现在没有返回只能继续等待。主线程也在等待所有任务完成后返回(主线程等待任务二完成后返回,任务二在等待主线程完成后更新UI所以任务二永远没法完成)造成死锁
解决办法:
一.都用BeginInvoke
void SetLable2Text()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":"+Thread.CurrentThread.ThreadState.ToString());
label2.Invoke(new Action(() =>
{
// Thread.Sleep(TimeSpan.FromSeconds(2));
label2.Text = "执行完毕";
Console.WriteLine("Method=2, Thread={0}", Thread.CurrentThread.ManagedThreadId);
}));
}
二. 把Parallel.Invoke放到子线程
ThreadPool.QueueUserWorkItem(w =>
{
tThread.ThreadState.ToString());
Parallel.Invoke(
()=> { Console.WriteLine("Lable1:coutn:0" + "," + Thread.CurrentThread.ManagedThreadId + ":" + Thread.CurrentThread.ThreadState.ToString()); },
SetLable2Text,
SetLable1Text
);
});