在后台工作程序中关闭 com 端口时应用程序崩溃 - C# 应用程序?

Application crash when close com port in a background worker - C# application?

我进行了快速搜索,但仍然找不到问题的答案。

串口变量

int close;
SerialPort _serialPort = new SerialPort("COM1", 1200, Parity.None, 8, StopBits.One);

串口委托代码

private void si_DataReceived(string data)
{
    if (close == 1)
    {
        string d1 = data.Trim().Replace("TT", "");
        d1 = d1.Replace("Tl3", "");
        txtCan.Text = d1;
    }
    else
    {
        return;
    }

}
private delegate void SetTextDeleg(string text);
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    string data = _serialPort.ReadLine();
    this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
}

连接按钮代码

private void button4_Click(object sender, EventArgs e)
{
    if (button4.Text == "Close Connection")
    {
        progressBar1.Style = ProgressBarStyle.Continuous;
        progressBar1.MarqueeAnimationSpeed = 0;
        close=0;
        try
        {
            string d1 = txtCan.Text;
            double r1 = Convert.ToDouble(d1) * 10;
            txtCan.Text = Math.Round(r1, 3).ToString();
            button4.Text = "Open Connection";
            button1.Enabled = true;
            readOnly(true);
        }
        catch (Exception ex)
        {
            button4.Text = "Open Connection";
            button1.Enabled = true;
            progressBar1.Style = ProgressBarStyle.Continuous;
            progressBar1.MarqueeAnimationSpeed = 0;
            MessageBox.Show("Cant connect.");
        }
    }
    else
    {
        progressBar1.Style = ProgressBarStyle.Marquee;
        progressBar1.MarqueeAnimationSpeed = 30;
        close = 1;
        txtCan.Text = "";
        txtCan.Focus();
        readOnly(false);
        button1.Enabled = false;
        button4.Text = "Close Connection";
        try
        {
            if(!_serialPort.IsOpen)
            { 
                _serialPort.Handshake = Handshake.None;
                _serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                _serialPort.Open();
            }
        }
        catch
        {
            button4.Text = "Open Connection";
            button1.Enabled = true;
            readOnly(true);
            progressBar1.Style = ProgressBarStyle.Continuous;
            progressBar1.MarqueeAnimationSpeed = 0;
            MessageBox.Show("Cant connect.");
        }
    }
}

我关闭 com 端口的解决方案,但如果我在可计数的时间内重新打开一个表单,它将失败(比如两次或三次,然后它会崩溃)

private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
    if (_serialPort.IsOpen)
    {
        e.Cancel = true; 
        Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); 
        CloseDown.Start();
    }
}

private void CloseSerialOnExit()
{
    try
    {
        backgroundWorker1.RunWorkerAsync();
    }
    catch (Exception ex)
    {
    }
    this.BeginInvoke(new EventHandler(NowClose)); 
}

private void NowClose(object sender, EventArgs e)
{
    this.Close(); //now close the form
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    _serialPort.Close(); 
}
    string data = _serialPort.ReadLine();

此语句不乏潜在 问题。当此调用未完成时,您手上有一个非常讨厌的故障模式。没必要,你可能会在错误的时间关闭串口设备,猛拉电缆,损坏线路终端器,你会非常头疼。

在任何事件处理程序停止 运行 之前,SerialPort.Close() 方法无法完成。这会显着增加死锁的几率。使用 ReadLine() 方法很好,但是你 必须将 ReadTimeout 属性 设置为,比如说,10 秒,这样你就可以确保事故不会发生变成不可调试的问题。让 TimeoutException 终止您的程序或设置一个 "serial port is dead" 状态变量。

通过取消 SerialPort 的生命周期与窗体的生命周期的关联,进一步提高成功几率。一般来说,唯一明智的做法是在程序启动时创建实例,直到程序终止才关闭它。放在单独的class里就行了,可以static方便使用

而且,出乎意料的是,现在调用 Close() 已不再重要。终结器会处理它。

另外请确保,如果您使用 USB 模拟器,永远不会断开它而不通过安全删除硬件托盘图标。 USB 驱动程序通常很难处理意外删除。有些太差了,即使你打开了它,它们也会让设备消失。并且尝试关闭它总是失败,你不能再干净地退出你的程序了。