System.IO.IOException:连接到系统的设备无法正常运行 C# .NET 4.0 [英] System.IO.IOException: A device attached to the system is not functioning C# .NET 4.0

查看:135
本文介绍了System.IO.IOException:连接到系统的设备无法正常运行 C# .NET 4.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我构建了一个从串行端口读取和写入数据的 C# 应用程序.连接到串行端口的设备是 FTDI USB 到串行转换器,它通过 XBee 无线模块与硬件通信.硬件测试电池模块的容量和稳态电压等.这些测试需要几天时间才能完成.

I've built a C# application which reads and writes data from a serial port. The device connected to the serial port is a FTDI USB to serial converter which communicates to hardware through a XBee wireless module. The hardware tests battery modules for capacity and steady state voltage etc. these tests take days to complete.

串行端口似乎时不时地停止响应并抛出 System.IO.IOException:连接到系统的设备没有运行错误.

Every now and then the serial port seems to stop responding and throws a System.IO.IOException: A device attached to the system is not functioning error.

这是堆栈跟踪:

at system.IO.Ports.InternalResources.WinIOError
at system.IO.Ports.SerialStream.EndWrite
at system.IO.Ports.SerialStream.Write
at system.IO.Ports.SerialPort.Write
at BatteryCharger.CommunicationClass.ApiTransmission

抛出此错误后,System.UnauthorizedAccessException: Access to the port is denied 错误被抛出,每次软件尝试写入端口时都会发生此错误,并且在我停止之前它永远不会恢复调试并重新启动软件只是为了几天后发生同样的事情.

after this error is thrown a System.UnauthorizedAccessException: Access to the port is denied error is thrown and this error occurs every time the software tries to write to the port and it never recovers until i stop debugging and restart the software only for the same thing to happen a few days later.

我该如何防止这个错误的发生,或者有没有办法在错误的 catch 语句中成功地从这些错误中恢复?

我在后台工作线程中连续读取串行端口并从不同线程写入.

I'm reading the serial port continuously in a background worker thread and writing from a different thread.

我也已经尝试了本论坛上建议的所有遗留错误处理零碎部分,但它们似乎没有任何区别.错误发生在 Windows XP Pro SP3 32 位和 Windows7 Pro 32 位.

I've also already tried all the legacy error handling bits and pieces that have been suggested on this forum but none of them seem to make any difference. The error occurs on windows XP Pro SP3 32bit and Windows7 Pro 32bit.

这是 CommunicationClass.cs - 串行传输代码.

Here is the CommunicationClass.cs - serial transmission code.

    public static bool ApiTransmission(TXpacket transmission)
    {
        //clear all previous data that may have been in the buffer before doing a transmission
        Variables.dataParserPacket_buff.Clear();
        //TXpacket xbeetransmision = new TXpacket();
        byte[] packet = transmission.GeneratePacket();

        try
        {
            if (_serialPort.IsOpen)
            {
#if Console
                Log.write("TX-Packet: " + StringHandler.listToString(packet.ToList<byte>()));
#endif
                _serialPort.Write(packet, 0, packet.Length);
                Thread.Sleep(100);
            }
            else
            {
#if Console
                Log.write("serial port is closed");
#endif
                return false;
            }
        }
        catch (UnauthorizedAccessException ex)
        {
            MessageBox.Show(ex.ToString());
            Log.write("UnauthorizedAccessException");
        }
        catch (IOException ex)
        {
            MessageBox.Show(ex.ToString());
            Log.write("IOexception");
            //_serialPort.Close();
            //Thread.Sleep(100);
            //_serialPort.Open();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
#if Console
            Log.write(ex.ToString());
#endif
        }
        return true;

    }

这就是我初始化串口的方式

This is how I initialize my serial port

    public CommunicationClass(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
    {
        _analysePacketBGW.DoWork += new DoWorkEventHandler(_analysePacketBGW_DoWork);
        _analysePacketBGW.WorkerReportsProgress = true;
        _analysePacketBGW.WorkerSupportsCancellation = true;

        _readBGW.DoWork += new DoWorkEventHandler(_readThread_DoWork);
        _readBGW.WorkerSupportsCancellation = true;
        _readBGW.WorkerReportsProgress = true;

        _parserStarterBGW.DoWork += new DoWorkEventHandler(_parserStarterThread_DoWork);
        _parserStarterBGW.WorkerSupportsCancellation = true;
        _parserStarterBGW.WorkerReportsProgress = true;
        if (_readBGW != null)
        {
            _readBGW.CancelAsync();
        }

        _serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);

        //SerialPortFixer.Execute(portName);
        //Thread.Sleep(1000);
        //using (_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits))
        //{
        //    //_serialPort.Open();
        //}

        _serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(_serialPort_ErrorReceived);

        _dataqueuepp = new ManualResetEvent(false);

        _serialPort.Open();
        _readBGW.RunWorkerAsync();
        _parserStarterBGW.RunWorkerAsync();
        CommunicationClass.PacketReceived += new DataPacketReceived(CommunicationClass_PacketReceived);
    }

以及处理串口读取的后台worker

And the background worker that handles the reading of the serial port

    void _readThread_DoWork(object sender, DoWorkEventArgs e)
    {
#if Console
        Log.write("Read()");
#endif
        while (!_readBGW.CancellationPending)
        {
            try
            {
                int message = _serialPort.ReadByte();
                try
                {
                    Variables.dataQueue.Enqueue(message);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "     " + message.ToString());
                }
                _dataqueuepp.Set();
                //Console.Write(String.Format("{0:X2}", message) + " ");
            }
            catch (TimeoutException) { Log.write("read timeout"); }
            catch (IOException) { Log.write("read IOException"); }
            catch (ThreadAbortException) { Log.write("read thread aborted"); }
            catch (Exception ex) { MessageBox.Show(ex.ToString()); }
            finally { }
        }
    }

我现在将重写代码以从同一线程读取和写入串行端口,看看这是否有任何区别.

I will now rewrite the code to read and write to/from the serial port from the same thread to see if that makes any difference.

编辑

根据 Jim 的评论,我在 IOException Catch 语句中添加了以下内容:

Based on Jim's comments I've added the following to the IOException Catch statement:

        catch (IOException ex)
        {
            MessageBox.Show(ex.ToString());
            Log.write("IOexception");
            _readBGW.CancelAsync();
            Thread.Sleep(100);
            _serialPort.Close();
            Thread.Sleep(100);
            _serialPort.Open();
            Thread.Sleep(100);
            _readBGW.RunWorkerAsync();
            _serialPort.Write(packet, 0, packet.Length);
        }

希望通过停止后台工作程序的 _serialPort.Read、关闭端口、重新打开端口、再次运行后台工作程序并再次尝试编写相同的命令,就足以成功地从此错误中恢复.MessageBox 仍然会阻止代码,以便我可以看到错误何时发生并可以监控它是如何恢复的.

Hopefully by stopping the background worker's _serialPort.Read, closing the port, re-opening the port, running the background worker again and attempting to write the same command again will be enough to successfully recover from this error. The MessageBox still blocks the code so that i can see when the error occurs and can monitor how it recovers.

我不喜欢像这样修补软件,但如果它有效,那么它就有效.

I don't like patching software like this but if it works then it works.

编辑 2

添加上面的代码后,我的软件再次崩溃,但现在当我调用 _serialPort.Close(); 时,它抛出UnauthorizedAccessException - 访问端口被拒绝";

After adding the code above my software crashed again but now it throws an "UnauthorizedAccessException - Access to the port is denied" when i call _serialPort.Close();

System.UnauthorizedAccessException was unhandled
Message=Access to the port is denied.
Source=System
StackTrace:
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.InternalResources.WinIOError()
at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Ports.SerialPort.Dispose(Boolean disposing)
at System.IO.Ports.SerialPort.Close()
at BatteryCharger.CommunicationClass.ApiTransmission(TXpacket transmission) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 436
at BatteryCharger.CommunicationClass.tx1(TXpacket packet, String callingMethod) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\CommunicationClass.cs:line 356
at BatteryCharger.XBee.setPin(String pinID, Byte status, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 215
at BatteryCharger.XBee.setPins(Int32 pins, XBee slave) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\XBee.cs:line 177
at BatteryCharger.BatteryCharger.requestVoltage(Int32 block) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 595
at BatteryCharger.BatteryCharger.requestVoltages() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\BatteryCharger.cs:line 612
at BatteryCharger.Form1.RunCommandOn(List`1 battList, Int32 command, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 522
at BatteryCharger.Form1.chargeBlock(Int32 blockNr, Double lowerLimit, Double upperLimit) in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 689
at BatteryCharger.Form1.<btnCheckCapacities_Click>b__13() in E:\Mijn Documenten\Research\Copy of BatteryCharger_V12\BatteryCharger\Form1.cs:line 619
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: 

这里发生了什么?

推荐答案

根据我的经验,10 次中有 9 次发生这种情况是因为另一个线程(终止或未终止)没有对硬件端口的独占访问权.

In my experience 9 times out of 10 this happens when another thread (terminated or not) doesn't have exclusive access to the hardware port.

尝试使用 SyncLock 为端口操作编写包装器,最重要的是它的打开/关闭.https://msdn.microsoft.com/en-us/library/3a86s51t.aspx

Try writing a wrapper for the port operations, most importantly the open/closing of it, using SyncLock. https://msdn.microsoft.com/en-us/library/3a86s51t.aspx

同样,我通常认为 try/catches 控制硬件是一种不好的做法,除非有足够的异常处理.

On a similar note, I would generally consider try/catches controlling hardware a bad practice, unless there's adequate exception handling.

原因(可能适用于此)是在抛出异常的情况下,硬件将锁定,更糟糕的是,异常将掩盖错误的真正原因.

The reason (which could apply here) is that in the case where an exception is thrown the hardware will lock, and what is worse, the exception will mask the true cause of the error(s).

在上面的代码中,我看到了

In the code above I see output of messages in the style

DebugPrint(ex.Message); 

这样做会更好

DebugPrint(ex.tostring()); 

因为这也将导出异常中的堆栈跟踪.

as this will also export the stack trace in the exception.

我要做的是实现一个异常记录器,将这些异常写入正在运行的计算机中某处的(带时间戳的)文本文件.跟踪记录的异常数据(连同所有相关信息)可以更好地理解为什么会发生这种情况.

What I would do is implement an exception logger that writes those exceptions to a (time stamped) text file somewhere in the computer this is running. Following on the exception data logged (along with all pertinent information) can lead to a better understanding why exactly this happens.

这篇关于System.IO.IOException:连接到系统的设备无法正常运行 C# .NET 4.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆