2012-04-24 58 views
2

在一个异步的OnMsgRecieved调用中,如果我直接给一个控件赋值,它就不起作用。 然后我才知道这是由于线程不安全,我得到以下代码来解决问题。 现在它工作。但我不确定它在实际中的作用。任何人都可以让我完全理解它吗? 的代码是: -windows窗体线程究竟发生了什么?

 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 :"; 
     } 
    } 

回答

1

当ShowResponseMessage上被调用该UI的一个不同的线程,则InvokeRequired将返回true,那么你正在使用Control.Invoke将消息发送到Windows消息队列。

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

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

+0

是否存在与同步上下文相关的内容? – userGS 2012-04-24 05:46:06

+0

谢谢,实际解释! – 2012-04-24 06:15:30

0

UI控件不能更新/从除主线程以外的任何线程改变/线程创建它上。

在你的情况下,检查InvokeRequired做检查,看看是否希望改变控制的线程是创建线程,如果没有传递回主线程/创建者。

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

如果使用多线程来提高你的Windows窗体 应用程序的性能,你必须确保你做在一个线程安全的方式你 控件的调用。

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

从不是使用Invoke方法创建控件的线程调用控件是不安全的。