代表和跨线程异常

时间:2010-04-20 06:25:59

标签: c# delegates multithreading

每当我使用委托更新Windows窗体中的UI时,它会给我跨线程异常 为什么会这样? 是否为每个委托调用启动了新线程?

void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
       //this call delegate to display data
       clsConnect(statusMsg);
}




 protected void displayResponse(string resp)
 {
     //here cross thread exception occur if directly set to lblMsgResp.Text="Test";
     if (lblMsgResp.InvokeRequired)
     {
        lblMsgResp.Invoke(new MethodInvoker(delegate { lblMsgResp.Text = resp; }));
     }
 }

4 个答案:

答案 0 :(得分:5)

在线程池线程上引发DataReceived事件始终。您无法更新任何UI控件, 使用Control.BeginInvoke()。没有必要测试InvokeRequired,它总是如此。

这里要记住以下几点:

  • 不要为您收到的每个字符或字节调用Control.BeginInvoke。这将使UI线程陷入困境。缓冲从串行端口获得的数据,直到获得完整的响应。使用SerialPort.ReadLine()通常运行良好,许多设备发送由换行符(SerialPort.NewLine)终止的字符串。
  • 关闭程序可能很困难。您必须确保表单保持活动状态,直到串行端口停止发送。在窗体关闭后获取事件将生成ObjectDisposed异常。使用FormClosing事件关闭串行端口并启动一秒计时器。只有在计时器到期时才真正关闭表单。
  • 避免使用Control.Invoke而不是BeginInvoke。当您调用SerialPort.Close()时,它可能会使程序死锁。

有很多方法可以解决问题。请考虑使用您自己的线程,而不是使用DataReceived来避免它们。

答案 1 :(得分:2)

Port_DataReceived显然是由端口监视组件上的线程引发的异步事件处理程序。

  

是否为每个线程启动了新线程   代表电话?

不,可能不是。您的端口监视组件正在后台线程上运行轮询,并且每次都从该线程引发事件。

重点是它是在UI以外的线程上调用的,因此您需要使用Control.Invoke以及与之关联的模式。

考虑一下,(并阅读post可能会为你阐明事物)

void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
   //this call delegate to display data
   UpdateTheUI(statusMsg);
}

private void UpdateTheUI(string statusMsg)
{
    if (lblMsgResp.InvokeRequired)
    {
        lblMsgResp.BeginInvoke(new MethodInvoker(UpdateTheUI,statusMsg));
    }
    else
    {
       clsConnect(statusMsg);
    }
}

尽管如此,如果我没有指出间接是令人不安的话,我会失职。

答案 2 :(得分:0)

当某些无UI线程更改UI元素时,会发生交叉线程异常。由于UI元素只应在UI线程中更改,因此抛出此异常。为了帮助您了解发生这种情况的原因,您必须发布代码。

答案 3 :(得分:0)

当某些无UI线程更改UI元素时,会发生跨线程异常。要解决此问题,请在控件本身上使用Invoke方法。另外,您可以在调用Invoke方法之前检查控件上的InvokeRequired 见msdn