HL-SDK
HL-SDK

Reputation: 160

Why does 'using' statement not seem to release serial port?

I am developing a C# WinForms Windows application that runs from the tray. I need to provide some reasonable level of error handling and instruction to the user. In order to test if I am able to open a serial port for communication, I wish to have a way to test if it is already open or if it is unopenable for whatever reason.

I came up with this:

if (SerialPort.GetPortNames().Select((n) =>
    n.ToUpperInvariant()).Contains(mycomportname))
{
    // Port found, check to see if we can use it by test-opening
    using (var sp = new SerialPort(mycomportname))
    {
        // Check to see if we can open this port
        try
        {
            if (sp.IsOpen) throw new Exception("Serial port is already open");
            sp.Open();
            sp.Close();
        }
        catch (Exception ex)
        {
            throw new Exception("Serial port is in use");
        }
    } 
}
else
{
    // ...
}

commManager.PortName = mycomportname;
if (commManager.OpenPort())
{
    // .. always returns false because causes UnauthorizedAccessException on open
}

For some reason the serial port does not seem to be fully released by the 'using' statement. The UnauthorizedAccessException does not occur when I delete the using statement and the statements inside it. How do I write robust error-tolerant serial port opening code?

Upvotes: 1

Views: 895

Answers (1)

Hans Passant
Hans Passant

Reputation: 941307

The MSDN article for SerialPort warns about this explicitly, albeit vaguely. SerialPort uses a worker thread to generate events like DataReceived and ErrorReceived. That thread gets started when you call Open() but it needs time to exit again after you call Close() or Dispose(). The physical port is in use until that happens. Exactly how long that takes is unpredictable. Usually within a millisecond but the worst-case is seconds when the machine is heavily loaded. Your code only waits for a nanosecond so you'll always get an exception.

The approach otherwise just doesn't make sense. Once you opened the port and got no exception then just keep it open. No point in closing it again and reopening it. Which is the simple solution.

And never do this kind of port scanning when GetPortNames() returns more than one port. The odds that the first one will open are very high, the odds that it is the right one are low. Murphy ensures that fifty-fifty odds turn into 1%. You always need to provide a config file so the user can pick the correct one. Only consider doing the port scanning when you populate a combobox with choices in a config helper window. Only skimp on this if you are in control over the machine configuration, that's pretty rare.

Upvotes: 5

Related Questions