什么原因导致我的UI在关闭串口时冻结?

Sae*_*ani 2 .net c# serial-port winforms

我正在开发一个串口相关的应用程序.使用I DataReceived事件SerialPort需要使用接收的字节更新文本框:

private void Connection_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var data = Connection.ReadExisting();
    _readBuffer.Add(indata);

    Invoke(new EventHandler(AddReceivedPacketToTextBox));       
}
Run Code Online (Sandbox Code Playgroud)

所以我Invoke用来更新文本框.但是有一个大问题.当我尝试关闭连接时,我的UI被冻结了,我认为这可能是因为Invoke正在做一些事情.

一位朋友说我应该用RequiredInvoke,但我不知道他真的是什么.如何在不搞乱调用和UI线程的情况下关闭连接?

这是我的近距离方法:

private void DisconnectFromSerialPort()
{
    if (Connection != null && Connection.IsOpen)
    {
        Connection.Close();            
    }
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

正如汉斯所说我改变InvokeBeginInvoke但现在情况有点糟糕,我的应用程序InvalidOperationException因为收集_readBuffer被修改而停止工作(这就是VS中的细节所说的)

这是我在文本框中添加文本的代码:

private void AddReceivedPacketToTextBox(object sender, EventArgs e)
{

    foreach (var i in _readBuffer)
        tbIn.Text += string.Format("{0:X2} ", i);

    tbIn.Text += Environment.NewLine;

    ScrollToBottom(tbIn);

    label4.Text = _receivedPackets.ToString();
    _receivedPackets++;

    _readBuffer.Clear(); //Possibly because clearing collection gets out of sync with BeginInvoke??         
}
Run Code Online (Sandbox Code Playgroud)

第二次更新

我仍然有问题,改变了Invoke()BeginInvoke没;吨帮助.我还尝试添加断开连接以形成关闭事件nu成功...任何时候我关闭我的表单它得到股票(我的意思是它的父表单,因为这个有权访问serialport的表单是从另一个表单`调用.

我的意思是我发现UI只在两种情况下被锁定:如果我计时调用按钮,Connection.Close() 如果我尝试关闭表单,那么父表单将抛出一些对象被处置的异常.

我从父表单中调用这样的串行表单:

public DebugForm DebugForm;

private void button1_Click(object sender, EventArgs e)
{
    if (DebugForm != null)
    {
        DebugForm.BringToFront();
        return;
    }

    DebugForm = new DebugForm();
    DebugForm.StartPosition = FormStartPosition.CenterScreen;
    DebugForm.Closed += delegate
                             {
                                 WindowState = FormWindowState.Normal;
                                 DebugForm = null;
                             };

    DebugForm.Show();
    WindowState = FormWindowState.Minimized; 
}
Run Code Online (Sandbox Code Playgroud)

这可能是问题吗?!

Han*_*ant 7

是的,这段代码在Close()调用中导致死锁的几率非常高.在DataReceived事件处理程序停止运行之前,串行端口无法关闭.但是,在UI线程空闲并泵送消息循环之前,Invoke()调用无法完成.它不是空闲的,它停留在Close()调用中.所以事件处理程序无法取得进展,因为它停留在Invoke()调用中,并且你的主线程无法取得进展,因为它停留在Close()调用,死锁城市.

最好的解决方法是使用BeginInvoke(),而不是阻止事件处理程序.根本没有关闭串口是另一种解决方法,这是可以的,因为Windows会在程序终止时自动处理它.通常,在设备忙于发送数据时关闭串行端口是不确定的,并且不可避免地导致数据丢失.好的,当你调试你的代码但不是你通常希望在生产中看到的东西时.