This is a major issue - I use a serial port in an application here and I poll the status of the attached device by opening and then closing the port again.
If the device fails, SOMETIMES the SerialPort.Close() - method NEVER returns and t开发者_C百科his is really a show stopper.
The worst thing is that even shutting down the application using the taskmanager fails, it doesn't work (or it is forbidden, by chance).
The attached device is a POS printer (USB) which simulates COM3, it's an Epson TM-T88IV (a very good model, btw).
Does anyone of you have experience with that?
Repeatedly opening and closing the port is not recommended. Check the Remarks section in the MSDN Library article for SerialPort.Close(). There's a background thread that needs to shut down before a port can be opened again, that takes time. The amount of time is not predictable.
The Close() method can easily deadlock if the DataReceived event handler is currently running. The most typical way to get the deadlock is calling Control.Invoke() in the event handler. Make sure you don't use any code in the event handler that blocks or requires a thread context switch. Using BeginInvoke() is fine.
Not being able to kill the program is caused by a problem in the serial port device driver. Start Taskmgr.exe, Process tab, View + Select Columns and tick "Handles". If after killing the program, you see the Handles column showing 1 then the serial port driver is hanging on to an I/O request that it doesn't complete. The process cannot terminate until all its kernel mode threads are exited.
There's little you can do about that particular problem, other than hoping for a driver update or switching to another vendor. Especially USB serial port emulators are notorious for having lousy device drivers. You get rid of a troublemaker like that by taking it out the parking lot and running it over with your car several times.
Another typical problem with USB emulators is that they are so easy to disconnect while they are in use. That works about as well as jerking a flash drive out of the socket while Windows is writing to it. It would also be a good way to get the device driver hung .NET versions prior to version 4.0 suffer from a heart attack in a background thread when the device suddenly disappears. Short from upgrading, a small sign next to the connector that says "Do not disconnect while in use!" is a practical workaround. They will anyway but get bored with it after a couple of times.
Fwiw, this is otherwise why the "Safely Remove Hardware" tray icon exists. You'll get a solid "Don't do it!" error as long as your program has the port in use. But of course, the operating system is powerless to get users to actually use it. Apple has a patent on a technique to make it fail-safe, detecting the user's fingers on the device :)
Prior to .Net 4.0 a lot could go wrong with USB to SerialPort devices(crash program/system, etc.). It was easy to test the errors by pulling the USB adapter with the port active.
Recently I ran some tests using .Net 4.0 and it is fixed(certainly improved)??? The test was a simple RX / TX through a USB SerialPort with a loopback, and pull the USB adapter while in use. My program did not crash, and I was able to re-open the port! This is a major improvement.
While it is sometimes a problem that the SerialPort.Close
method deadlocks, that should not prevent Task Manager from killing your process. If you can't kill your process, this is almost certainly due to a bug in the USB serial driver. Unfortunately, your options are most likely these:
- don't poll for device status
- get the vendor to fix the bug
- work around the problem by figuring out a way to poll the device status without accessing the serial port
- work around the problem by accessing the device via some other method (perhaps direct USB manipulation)
Not possible?
I've got an idea:Put a flag inside the data recieve event that will close the serialcom from inside! Simple!
trying it my self now
What about using BackGround thread to poll the device so that it does not stop your application from exiting?
you can use this :
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_serialPort.IsOpen)
{
e.Cancel = true; //cancel the fom closing
Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); //close port in new thread to avoid hang
CloseDown.Start(); //close port in new thread to avoid hang
}
}
private void CloseSerialOnExit()
{
try
{
_serialPort.Close(); //close the serial port
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); //catch any serial port closing error messages
}
this.Invoke(new EventHandler(NowClose)); //now close back in the main thread
}
private void NowClose(object sender, EventArgs e)
{
this.Close(); //now close the form
}
精彩评论