当涉及到窗口GUI控制时,我应该只使用BeginInvoke而不是Invoke吗
本文关键字:BeginInvoke Invoke 我应该 窗口 GUI 控制 | 更新日期: 2023-09-27 18:22:09
我正在学习GUI线程与Worker线程的行为
所以我创建了一个类,它将从不同的线程更新GUI控件。。。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("'n'n'n");
Thread.CurrentThread.Name = "Parent Thread";
label1.Text = "I am One";
System.Diagnostics.Debug.WriteLine("[button1_Click] label1.Text :" + label1.Text);
Thread _Thred = new Thread(FunctionCallBack);
_Thred.Name = "Child Thread";
_Thred.Start();
_Thred.Join();
label1.Text = "I am Three";
System.Diagnostics.Debug.WriteLine("[button1_Click] label1.Text :" + label1.Text);
}
void FunctionCallBack()
{
MethodInvoker _Method = delegate()
{
label1.Text = "I am Two";
System.Diagnostics.Debug.WriteLine("[FunctionCallBack] label1.Text :" + label1.Text);
};
System.Diagnostics.Debug.WriteLine("[FunctionCallBack] label1.BeginInvoke(_Method) : Executed");
label1.BeginInvoke(_Method);
/*
System.Diagnostics.Debug.WriteLine("[FunctionCallBack] label1.Invoke(_Method) : Executed");
label1.Invoke(_Method);
*/
}
}
当我点击按钮时,我得到这个输出
Output when I using BeginInvoke Method
--------------------------------------
[button1_Click] label1.Text :I am One
[FunctionCallBack] label1.BeginInvoke(_Method) : Executed
The thread 'Child Thread' (0xfb8) has exited with code 0 (0x0).
[button1_Click] label1.Text :I am Three
[FunctionCallBack] label1.Text :I am Two
我使用Invoke
方法而不是调用BeginInvoke
方法来更改代码。
System.Diagnostics.Debug.WriteLine("[FunctionCallBack] label1.Invoke(_Method) : Executed");
label1.Invoke(_Method);
我得到低于输出和程序停止。
Output when I using Invoke Method
----------------------------------
[button1_Click] label1.Text :I am One
[FunctionCallBack] label1.Invoke(_Method) : Executed
请让我知道,我现在面临的这种情况叫dead lock
吗
如果你同意,我有机会再次使用Control.Invoke
方法吗?
尤其是在这种情况下,我只有一次机会使用Control.BeginInvoke
方法吗?
我们将感谢您的每一个建议。
问题出在button_Click方法上。它在GUI线程上被调用,在_thread.Join上被阻塞。你应该删除它,而不是等待线程完成;这就是在另一个线程上执行某个东西的全部想法。
第一种情况之所以有效,是因为工作线程不等待GUI线程更新,然后返回,这样GUI线程就被解除阻塞了。
在第二种情况下,工作线程等待GUI更新,但它不能更新,因为它在等待工作线程完成时被阻止了。是的,这是一个死锁,但问题实际上在于点击方法。
@RichardSchneider回答了死锁的原因。
线程处理很难做到正确,不要让它变得过于复杂。
- 避免裸线程,使用ThreadPool或BackgroundWorker
- 通常使用Control.BeginInvoke(),但如果调用太频繁,可能会淹没GUI线程。使用Control.Invoke()来限制后台线程。此外,它还有助于保持UI更新的有序性