Occasionally some of my integration tests are failing with the above message. I'm using the code below to ready the port.
for(int i = 0; i < 5; i++)
{
try
{
port.Open();
if (port.IsOpen)
break;
}
catch (Exception e)
{
try
{
port.Close();
}
catch (Exception)
{}
Thread.Sleep(300);
}
}
My assumption is that because it can't be the current thread blocking the port (because it will try to close it), it must be another thread or process that has died without cleaning up properly (one of the other tests - nothing else accesses this port). Is there a way to reset the state of the SerialPort
so that the new thread / process can access it again?
Thanks,
Richard
This is a flaw in the SerialPort class, it uses an internal helper thread to wait for events on the port. The source of the DataReceived, PinChanged and ErrorReceived events. The flaw is in the Close() method implementation, it doesn't wait for this helper thread to terminate. That takes time, the exact amount of time is not predictable and could be many seconds when the machine is particularly busy. The physical port doesn't get closed until this happens, opening the port before the thread exits bombs with a 'port already in use' exception. The one you get. Sleeping for 300 msec is thus not good enough.
This is not normally an issue, serial ports are not sharable devices. Closing a serial port and not exiting your program is dangerous, another process could steal the port. Also giving you this exception when you try to open it again. The normal practice is to open the port when your app starts and not close it until it terminates.
I routinely verify that the port is closed just before I instantiate a serial port. This helps if you stop debugging code without closing the serial port. Also you should wait 250 msec after opening or closing the port before you continue with your code.
try
{
if ((m_SerialPort != null))
{
if (m_SerialPort.IsOpen)
{
m_SerialPort.Close();
}
}
m_SerialPort = new SerialPort(portName, dataRate, parity, databits, stopBits.One);
m_SerialPort.Open();
if (!m_SerialPort.IsOpen)
{
MessageBox.Show(string.Concat(portName, " failed to open"));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With