当涉及到窗口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方法吗?

我们将感谢您的每一个建议。

当涉及到窗口GUI控制时,我应该只使用BeginInvoke而不是Invoke吗

问题出在button_Click方法上。它在GUI线程上被调用,在_thread.Join上被阻塞。你应该删除它,而不是等待线程完成;这就是在另一个线程上执行某个东西的全部想法。

第一种情况之所以有效,是因为工作线程不等待GUI线程更新,然后返回,这样GUI线程就被解除阻塞了。

在第二种情况下,工作线程等待GUI更新,但它不能更新,因为它在等待工作线程完成时被阻止了。是的,这是一个死锁,但问题实际上在于点击方法。

@RichardSchneider回答了死锁的原因。

线程处理很难做到正确,不要让它变得过于复杂。

  • 避免裸线程,使用ThreadPool或BackgroundWorker
  • 通常使用Control.BeginInvoke(),但如果调用太频繁,可能会淹没GUI线程。使用Control.Invoke()来限制后台线程。此外,它还有助于保持UI更新的有序性