C# 带有SerialPort的Windows窗体-关闭窗体后应用程序挂起
我有一个windows窗体应用程序,可以连接到Arduino板。当我想关闭它时,它将保持打开状态,直到我停止调试模式。当我在VisualStudio中运行程序时,以及当我单独运行C# 带有SerialPort的Windows窗体-关闭窗体后应用程序挂起,c#,multithreading,arduino,serial-port,C#,Multithreading,Arduino,Serial Port,我有一个windows窗体应用程序,可以连接到Arduino板。当我想关闭它时,它将保持打开状态,直到我停止调试模式。当我在VisualStudio中运行程序时,以及当我单独运行exe文件时,会发生这种情况,我必须从任务管理器中停止它 我尝试了FormClosing和FormClosing事件,但结果是一样的。我唯一想到的是,出现这种问题是因为我在我的SerialPort的datareceived事件中为我的控件使用了许多Invoke函数。我这样做是因为我需要对表单控件进行线程安全调用。以下是我
exe
文件时,会发生这种情况,我必须从任务管理器中停止它
我尝试了FormClosing
和FormClosing
事件,但结果是一样的。我唯一想到的是,出现这种问题是因为我在我的SerialPort
的datareceived
事件中为我的控件使用了许多Invoke
函数。我这样做是因为我需要对表单控件进行线程安全调用。以下是我代码的一部分:
private void spArduino_DataReceived(对象发送方,System.IO.Ports.SerialDataReceivedEventArgs e)
{
如果(spArduino.BytesToRead>0)
{
字符串数据=spArduino.ReadLine().Replace(“\r”,”);
if(数据启动方式(“当前温度:))
{
if(lbTemprature.invokererequired)
{
lbTemprature.Invoke(新方法调用器(委托{
lbTemprature.Text=“室温”+数据。删除(0,9)+“摄氏度”;
}));
}
}
}
}
///////
私有无效监视\u FormClosing(对象发送方,FormClosingEventArgs e)
{
尝试
{
spArduino.WriteLine(“清晰”);
spArduino.Close();
}
捕获(例外)
{
MessageBox.Show(“errorclose”);
}
}
这将显示在我的输出中(VisualStudio)
在我停止程序之前,它一直这样
有人能帮我了解我的问题在哪里以及如何解决吗?看看你是如何清理串行设备的。尝试取消订阅活动(即,
-=spArduino\u DataReceived
)。引用可能会阻止垃圾收集并在关闭后保持窗体的活动状态。在主UI线程之外的单独线程上触发SerialPort.DataReceived
事件,这就是为什么在更新UI时需要调用lbTemprature.Invoke
方法的原因
关闭窗体而不关闭端口
如果在不关闭端口的情况下关闭表单,则在关闭表单时,在释放表单后可能会触发DataReceived
事件,这将在尝试更新UI时导致异常
在关闭窗体之前关闭端口
如果在关闭窗体之前关闭端口(例如在FormClosing
事件中),则可能会遇到死锁,因为主UI线程中的SerialPort.close()
等待触发DataReceived
事件的线程完成事件,调用lbTemprature.Invoke
时,DataReceived
事件正在等待UI线程。这可能是导致窗体释放的原因
解决方案
解决方案可以调用lbTemprature.BeginInvoke
,以避免死锁。这可能还不够,因为在处理表单后,BeginInvoke
仍然可以运行,并导致期望值。可能需要向表单.IsDisposed
属性添加检查
if (lbTemprature.InvokeRequired)
{
lbTemprature.BeginInvoke(new MethodInvoker(delegate
{
if (!this.IsDisposed)
{
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}
}));
}
尝试注释掉spArduino_DataReceived中的所有内容,运行应用程序并尝试关闭。如果是,您与您的代表之间存在问题。猜测:
lbTemprature.Invoke
无法正常工作,spArduino
中的完整任务失败并阻塞UI。
if (lbTemprature.InvokeRequired)
{
lbTemprature.BeginInvoke(new MethodInvoker(delegate
{
if (!this.IsDisposed)
{
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}
}));
}