C# 委托和交叉线程异常

C# 委托和交叉线程异常,c#,delegates,multithreading,C#,Delegates,Multithreading,每当我使用委托更新windows窗体中的UI时,它都会给我一个跨线程异常 为什么会这样? 是否为每个委托调用启动了新线程 void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { //this call delegate to display data clsConnect(statusMsg); } protected void displayResponse(string

每当我使用委托更新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; }));
     }
 }

当一些非UI线程更改UI元素时,会发生跨线程异常。由于UI元素只应在UI线程中更改,因此会引发此异常。为了帮助您理解为什么会发生这种情况,您必须发布代码

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

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

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

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; }));
     }
 }
不,可能不会。端口监视组件正在后台线程上运行轮询,每次都会从该线程引发事件

关键是它是在UI以外的线程上调用的,因此您需要使用和它相关的模式

考虑一下这一点,(并阅读可能会为你带来启发的文章)

话虽如此,如果我没有指出间接寻址很麻烦,那我就是失职了。

DataReceived事件总是在线程池线程上引发的。无法更新任何UI控件,必须使用control.BeginInvoke()。测试invokererequired没有意义,它总是正确的

这里需要记住几件事:

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

有很多方法会惹上麻烦。请考虑使用自己的线程,而不是使用DATA接收来避免它们。

请张贴完全例外。CLSCONNEL调用DISPLAY响应。如果我正确理解,PATRYDATA最终接收到DISPLAY响应。如果是,则从另一个线程调用端口_DataReceived。IO API是否调用此方法?将
BeginInvoke
更改为
Invoke
,Hans是对的。我在编写CP代码时忽略了这一点。错误的做法是,Invoke()通常会导致Close()调用出现死锁。@Hans,显然你在处理这一问题上有更多的经验,我将恢复我的修订版,但为什么不添加一个代码示例,让我们检查一下你的答案。我会感觉好些的。