2011-09-08 65 views
7

有时候,我的一些集成测试与上述消息失败。我正在使用下面的代码准备端口。SerialPort UnauthorizedAccessException

  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); 
       } 
      } 

我的假设是,因为它不能被当前线程阻塞端口(因为它会尝试关闭它),它必须是一个没有正确清理死了另一个线程或进程(之一其他测试 - 没有其他人访问此端口)。有没有办法重置SerialPort的状态,以便新线程/进程可以再次访问它?

感谢,

理查德

回答

11

这是SerialPort类的一个缺陷,它使用一个内部辅助线程等待端口上的事件。 DataReceived,PinChanged和ErrorReceived事件的来源。该缺陷位于Close()方法实现中,它不会等待此辅助线程终止。这需要时间,确切的时间量是不可预测的,并且在机器特别忙时可能需要很多秒。在这种情况发生之前,物理端口并未关闭,在线程退出带有“端口已被使用”的炸弹例外之前打开端口。你得到的那个。因此睡300毫秒是不够好的。

这通常不是问题,串口不是可共享的设备。关闭串口并且不退出程序是危险的,另一个进程可能会窃取端口。当您尝试再次打开时也会给您这个例外。通常的做法是在您的应用程序启动时打开端口,并在其终止之前不关闭端口。

+0

感谢汉斯 - 这只发生在不同测试过程开始的测试中。 –

2

我不能看到你关闭端口。

对我来说,问题不在这里(即使你应该重构位代码),但可能是你在呼唤port.Open();当端口仍然是打开

从MSDN

只有一个打开的连接可以每个SerialPort对象都存在。

(我不能告诉你为什么,因为我没有足够的信息)请记住关闭方法需要一些时间来真正关闭端口,实际上你应该阻塞主线程直到端口有被关闭(可能使用的Thread.join)

从MSDN

任何应用最好的做法就是等待一定的时间试图调用Open方法之前调用Close方法之后,作为端口可能不会立即关闭。

更多信息

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

+0

@Massimilano - 谢谢你的回答。休眠300ms后(当打开失败时引发异常),端口在catch块中关闭。 –

+0

我可以看到,但只有在引发异常时才关闭端口。 如果port.Open()不会抛出异常,则不会执行.Close() –

+0

对不起,如果我不清楚。开放失败的原因是由于正在抛出UnauthorizedAccessException(这是我试图关闭的原因)。 –

4

我经常在我实例化一个串口之前验证端口是否关闭。这有助于在不关闭串口的情况下停止调试代码。在继续执行代码之前,您也应该在打开或关闭端口后等待250毫秒。

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); 
     } 
0

GC.SuppressFinalizeGC.ReRegisterForFinalize应该叫路过一个串口实例BaseStream属性作为参数,而不仅仅是一个串口实例。