Windows窗体线程究竟发生了什么?

时间:2012-04-24 05:20:44

标签: c# .net winforms multithreading thread-safety

在异步OnMsgRecieved调用中,如果我直接为控件赋值,则它无效。 然后我才知道这是由于线程不安全而且我得到了以下代码来解决问题。 现在它正在运作。但我不确定它实际上做了什么。谁能让我完全理解它? 代码是: -

        public void listener_OnMsgRecieved(string aResponse)
    {
        ShowResponseMessage(aResponse);
    }

    public void ShowResponseMessage(string aResponse)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.listBox.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(ShowResponseMessage);
            this.Invoke(d, new object[] { aResponse });
        }
        else
        {
            this.listBox.Items.Add(aResponse);
            label.Text = "Response received from Server :";
        }
    }

2 个答案:

答案 0 :(得分:1)

当在与UI的线程不同的线程上调用ShowResponseMessage时,InvokeRequired将返回true,然后您使用Control.Invoke将消息发送到Windows消息队列。

在UI线程中运行的UI消息泵将拉出消息并将其传递给目标控件,然后目标控件看到这是一条消息,请求调用委托并由控件调用委托,现在,它正在UI线程上运行,因此交叉线程问题已得到解决。

诀窍是不直接在非UI调用线程上调用委托。使用Windows消息,执行委托的指令被传递给UI线程,然后UI线程执行委托以响应消息。 “Control.Invoke”使用Windows [SendMessage][1]Control.BeginInvoke使用[PostMessage][2] Win32 API来促进邮件传递。

答案 1 :(得分:0)

无法从创建主线程/线程以外的任何线程更新/更改UI控件。

在您的情况下,检查InvokeRequired会检查是否希望更改控件的线程是创建线程,如果没有将调用传递回主线程/创建者。

查看How to: Make Thread-Safe Calls to Windows Forms Controls

  

如果使用多线程来提高Windows的性能   表单应用程序,您必须确保拨打电话   以线程安全的方式控制。

     

对Windows窗体控件的访问本质上不是线程安全的。如果你   有两个或多个线程来操纵控件的状态,它是   可能迫使控件进入不一致状态。其他   线程相关的错误是可能的,例如竞争条件和   死锁。确保访问您的控件非常重要   以线程安全的方式执行。

     

在不使用Invoke方法的情况下,从创建控件的线程以外的线程调用控件是不安全的。