开发者

SerialPort UnauthorizedAccessException

Occasio开发者_运维技巧nally 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);
        }


I can't see where you close the port.

The issue for me is not here (even if you should refactor a bit the code) but probably you are calling port.Open(); when the port is still open

From MSDN

Only one open connection can exist per SerialPort object.

(I can't tell you why because I don't have enough information) Bear also in mind the the close method takes some time to actually close the port in fact you should block the main thread until the port has been close (perhaps using Thread.Join)

From MSDN

The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.

for more info

http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open.aspx


GC.SuppressFinalize should be called passing the SerialPort instance BaseStream property as the parameter and not just the SerialPort instance.

public class SerialConnection : SerialPort
{

    public new void Dispose()
    {
        if (_isDisposed)
            return;

        _isDisposed = true;
        BaseStream.Dispose();
        GC.SuppressFinalize(BaseStream);
        base.Dispose();
        GC.SuppressFinalize(this);
    }

The new void Dispose() of course is not the recommended way to implement IDisposable. It's merely a fix for the odd behaviour of the SerialPort class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜