Windows 带有 SerialPort 的表单 - 应用程序在关闭表单后挂起
Windows forms with SerialPort - app hangs after closing form
我有一个 windows 表单应用程序以连接到 Arduino 开发板。当我想关闭它时,它会保持打开状态,直到我停止调试模式。当我在 Visual Studio 中 运行ning 程序和我单独 运行 exe
文件时,会发生这种情况,我必须从任务管理器中停止它。
我尝试了 FormClosing
和 FormClosed
事件,但结果是一样的。我唯一想到的是这个问题的发生是因为我在 SerialPort
的 DataRecieved
事件中使用了许多 Invoke
函数来控制我的控件。我这样做是因为我需要对表单控件进行线程安全调用。这是我的代码的一部分:
private void spArduino_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (spArduino.BytesToRead > 0)
{
string data = spArduino.ReadLine().Replace("\r", "");
if (data.StartsWith("CUR_TEMP:"))
{
if (lbTemprature.InvokeRequired)
{
lbTemprature.Invoke(new MethodInvoker(delegate {
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}));
}
}
}
}
///////
private void Monitoring_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
spArduino.WriteLine("CLEAR");
spArduino.Close();
}
catch (Exception)
{
MessageBox.Show("errorclose");
}
}
这显示在我的输出中 (Visual Studio)
The thread 0x2bf0 has exited with code 0 (0x0).
The thread 0x5f24 has exited with code 0 (0x0).
The thread 0x46c4 has exited with code 0 (0x0).
The thread 0x5df4 has exited with code 0 (0x0).
The thread 0x294c has exited with code 0 (0x0).
The thread 0x4620 has exited with code 0 (0x0).
The thread 0x720 has exited with code 0 (0x0).
The thread 0x35a0 has exited with code 0 (0x0).
它一直保持这种状态,直到我停止程序。
任何人都可以帮助我了解我的问题在哪里以及我该如何解决?
查看您是如何清理串行设备的。尝试取消订阅活动(即 -= spArduino_DataReceived
)。引用可能会阻止垃圾收集并在关闭后使您的表单保持活动状态。
SerialPort.DataReceived
事件在与主 UI 线程不同的线程上触发,这就是为什么在更新 UI 时需要调用 lbTemprature.Invoke
方法的原因。
关闭窗体而不关闭端口
如果不关闭端口就关闭窗体,那么在关闭窗体时,可能会在窗体处理后触发DataReceived
事件,这会在尝试更新UI.
关闭窗体前关闭端口
如果您在关闭表单之前关闭端口(例如在 FormClosing
事件中),那么您可能会遇到死锁,因为主 UI 线程中的 SerialPort.Close()
等待触发DataReceived
事件的线程完成事件,DataReceived
事件在你调用lbTemprature.Invoke
时等待UI线程。这可能是导致表格冻结的原因。
解决方案
一个解决方案是调用lbTemprature.BeginInvoke
来避免死锁。这可能还不够,因为 BeginInvoke
在处理表单后仍然可以 运行 并引起期望。可能需要向 Form.IsDisposed
属性 添加支票。
if (lbTemprature.InvokeRequired)
{
lbTemprature.BeginInvoke(new MethodInvoker(delegate
{
if (!this.IsDisposed)
{
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}
}));
}
我有一个 windows 表单应用程序以连接到 Arduino 开发板。当我想关闭它时,它会保持打开状态,直到我停止调试模式。当我在 Visual Studio 中 运行ning 程序和我单独 运行 exe
文件时,会发生这种情况,我必须从任务管理器中停止它。
我尝试了 FormClosing
和 FormClosed
事件,但结果是一样的。我唯一想到的是这个问题的发生是因为我在 SerialPort
的 DataRecieved
事件中使用了许多 Invoke
函数来控制我的控件。我这样做是因为我需要对表单控件进行线程安全调用。这是我的代码的一部分:
private void spArduino_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (spArduino.BytesToRead > 0)
{
string data = spArduino.ReadLine().Replace("\r", "");
if (data.StartsWith("CUR_TEMP:"))
{
if (lbTemprature.InvokeRequired)
{
lbTemprature.Invoke(new MethodInvoker(delegate {
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}));
}
}
}
}
///////
private void Monitoring_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
spArduino.WriteLine("CLEAR");
spArduino.Close();
}
catch (Exception)
{
MessageBox.Show("errorclose");
}
}
这显示在我的输出中 (Visual Studio)
The thread 0x2bf0 has exited with code 0 (0x0).
The thread 0x5f24 has exited with code 0 (0x0).
The thread 0x46c4 has exited with code 0 (0x0).
The thread 0x5df4 has exited with code 0 (0x0).
The thread 0x294c has exited with code 0 (0x0).
The thread 0x4620 has exited with code 0 (0x0).
The thread 0x720 has exited with code 0 (0x0).
The thread 0x35a0 has exited with code 0 (0x0).
它一直保持这种状态,直到我停止程序。
任何人都可以帮助我了解我的问题在哪里以及我该如何解决?
查看您是如何清理串行设备的。尝试取消订阅活动(即 -= spArduino_DataReceived
)。引用可能会阻止垃圾收集并在关闭后使您的表单保持活动状态。
SerialPort.DataReceived
事件在与主 UI 线程不同的线程上触发,这就是为什么在更新 UI 时需要调用 lbTemprature.Invoke
方法的原因。
关闭窗体而不关闭端口
如果不关闭端口就关闭窗体,那么在关闭窗体时,可能会在窗体处理后触发DataReceived
事件,这会在尝试更新UI.
关闭窗体前关闭端口
如果您在关闭表单之前关闭端口(例如在 FormClosing
事件中),那么您可能会遇到死锁,因为主 UI 线程中的 SerialPort.Close()
等待触发DataReceived
事件的线程完成事件,DataReceived
事件在你调用lbTemprature.Invoke
时等待UI线程。这可能是导致表格冻结的原因。
解决方案
一个解决方案是调用lbTemprature.BeginInvoke
来避免死锁。这可能还不够,因为 BeginInvoke
在处理表单后仍然可以 运行 并引起期望。可能需要向 Form.IsDisposed
属性 添加支票。
if (lbTemprature.InvokeRequired)
{
lbTemprature.BeginInvoke(new MethodInvoker(delegate
{
if (!this.IsDisposed)
{
lbTemprature.Text = "Room temprature " + data.Remove(0,9) + "°C";
}
}));
}