优雅地杀死一个 Visual C++ 串行线程
Graciously killing a Visual C++ Serial thread
我有一个 Visual Studio C++ 2013 MFC 应用程序,它 writes/reads 来自串行旋转编码器的数据,并将读取的数据发送到步进电机。读数在一段时间内 (flagTrue) {}。 while 循环在一个单独的线程中假脱机。
它完成了工作,但是当我尝试优雅地退出应用程序时,我不断得到这个:
'System.ObjectDisposedException' mscorlib.dll
我尝试将计时器设置为 1-2 秒以让串行侦听结束,但即使我似乎已经退出线程,侦听似乎仍在继续。以下是代码片段:
//this is inside of the main window CDlg class
pSerialThread = (CSerialThread*)AfxBeginThread(RUNTIME_CLASS(CSerialThread));
//this is inside the CSerialThread::InitInstance() function
init_serial_port();
//this is the serial listening while loop
void init_serial_port() {
SerialPort^ serialPort = gcnew SerialPort();
while (bSerialListen) {
//do read/write using the serialPort object
}
serialPort->Close();
}
///this is in the OnOK() function
bSerialListen = false;
pSerialThread->ExitInstance();
一个不完整的解决方法,启发了汉斯在下面的回答,是让线程在端口关闭后重置一个标志:
SerialPort^ serialPort = gcnew SerialPort();
serialIsOpen = true;
while (bSerialListen) {
//do read/write using the serialPort object
}
serialPort->Close();
serialIsOpen = false;
}
然后在 OnOK() 内部(这确实会导致干净退出):
bSerialListen=false;
//do other stuff which normally takes longer than the port closing.
if (serialIsOpen) {
//ask user to press Exit again;
return;
}
OnOK();
}
但是,用户总是要按两次退出,因为下面的命令永远行不通
while (serialIsOpen) {
Sleep(100);
//safety counter, do not proceed to OnOK();
}
OnOK();
while 在端口重置标志之前过期,即使等待 10 秒——比用户按两次按钮的时间长得多:
while (bSerialListen) {
很麻烦。首先,从长远来看,bool 不是一个合适的线程同步原语。其次,肯定是最有可能的问题是您的代码没有检查它。因为线程 实际上 卡在了 SerialPort::Read() 调用中。未完成是因为设备在您要终止程序时未发送任何内容。
接下来发生的事情很少是优雅的。触发不可捕获的 ObjectDisposedException 的一个好方法是猛拉 USB 连接器。当您看到它不起作用并且不知道下一步该做什么时,您唯一可以做的另一件事。非常糟糕的主意。这让许多 USB 驱动程序厌恶地举起手来,它知道用户应用程序已经打开了端口,但它已经不存在了,现在开始失败任何请求。有时甚至关闭请求失败,非常不愉快。没有办法优雅地做到这一点,串行端口不是即插即用设备。这会在 SerialPort 开始引发事件的工作线程中触发 ODE,它是不可捕获的。
从不,从不,从不 猛拉 USB 连接器,使用 "Safely Remove Hardware" 托盘图标是一个坚如磐石的要求对于串行端口等遗留设备。不要勉强。
那么接下来要做什么?完成 SerialPort::Read() 调用的唯一优雅方法是猛拉地垫。您必须调用 SerialPort::Close()。您仍然会得到一个 ObjectDisposedException,但现在它是您可以实际捕获的异常。立即跳出循环,不要做任何事,让线程终止。
但是你当然必须从 另一个 线程这样做,因为这个被卡住了。毫无疑问,当您使用 MFC 时,这样做会遇到很多麻烦,希望它退出的线程不是您程序中的托管线程。听起来你已经发现了。
更好的方法是您阅读 this post 后可能会接受的方法。只是不要。
我有一个 Visual Studio C++ 2013 MFC 应用程序,它 writes/reads 来自串行旋转编码器的数据,并将读取的数据发送到步进电机。读数在一段时间内 (flagTrue) {}。 while 循环在一个单独的线程中假脱机。
它完成了工作,但是当我尝试优雅地退出应用程序时,我不断得到这个:
'System.ObjectDisposedException' mscorlib.dll
我尝试将计时器设置为 1-2 秒以让串行侦听结束,但即使我似乎已经退出线程,侦听似乎仍在继续。以下是代码片段:
//this is inside of the main window CDlg class
pSerialThread = (CSerialThread*)AfxBeginThread(RUNTIME_CLASS(CSerialThread));
//this is inside the CSerialThread::InitInstance() function
init_serial_port();
//this is the serial listening while loop
void init_serial_port() {
SerialPort^ serialPort = gcnew SerialPort();
while (bSerialListen) {
//do read/write using the serialPort object
}
serialPort->Close();
}
///this is in the OnOK() function
bSerialListen = false;
pSerialThread->ExitInstance();
一个不完整的解决方法,启发了汉斯在下面的回答,是让线程在端口关闭后重置一个标志:
SerialPort^ serialPort = gcnew SerialPort();
serialIsOpen = true;
while (bSerialListen) {
//do read/write using the serialPort object
}
serialPort->Close();
serialIsOpen = false;
}
然后在 OnOK() 内部(这确实会导致干净退出):
bSerialListen=false;
//do other stuff which normally takes longer than the port closing.
if (serialIsOpen) {
//ask user to press Exit again;
return;
}
OnOK();
}
但是,用户总是要按两次退出,因为下面的命令永远行不通
while (serialIsOpen) {
Sleep(100);
//safety counter, do not proceed to OnOK();
}
OnOK();
while 在端口重置标志之前过期,即使等待 10 秒——比用户按两次按钮的时间长得多:
while (bSerialListen) {
很麻烦。首先,从长远来看,bool 不是一个合适的线程同步原语。其次,肯定是最有可能的问题是您的代码没有检查它。因为线程 实际上 卡在了 SerialPort::Read() 调用中。未完成是因为设备在您要终止程序时未发送任何内容。
接下来发生的事情很少是优雅的。触发不可捕获的 ObjectDisposedException 的一个好方法是猛拉 USB 连接器。当您看到它不起作用并且不知道下一步该做什么时,您唯一可以做的另一件事。非常糟糕的主意。这让许多 USB 驱动程序厌恶地举起手来,它知道用户应用程序已经打开了端口,但它已经不存在了,现在开始失败任何请求。有时甚至关闭请求失败,非常不愉快。没有办法优雅地做到这一点,串行端口不是即插即用设备。这会在 SerialPort 开始引发事件的工作线程中触发 ODE,它是不可捕获的。
从不,从不,从不 猛拉 USB 连接器,使用 "Safely Remove Hardware" 托盘图标是一个坚如磐石的要求对于串行端口等遗留设备。不要勉强。
那么接下来要做什么?完成 SerialPort::Read() 调用的唯一优雅方法是猛拉地垫。您必须调用 SerialPort::Close()。您仍然会得到一个 ObjectDisposedException,但现在它是您可以实际捕获的异常。立即跳出循环,不要做任何事,让线程终止。
但是你当然必须从 另一个 线程这样做,因为这个被卡住了。毫无疑问,当您使用 MFC 时,这样做会遇到很多麻烦,希望它退出的线程不是您程序中的托管线程。听起来你已经发现了。
更好的方法是您阅读 this post 后可能会接受的方法。只是不要。