在后台工作程序中关闭 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 驱动程序通常很难处理意外删除。有些太差了,即使你打开了它,它们也会让设备消失。并且尝试关闭它总是失败,你不能再干净地退出你的程序了。
我进行了快速搜索,但仍然找不到问题的答案。
串口变量
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 驱动程序通常很难处理意外删除。有些太差了,即使你打开了它,它们也会让设备消失。并且尝试关闭它总是失败,你不能再干净地退出你的程序了。