草庐IT

c# - 系统.IO.IOException : A device attached to the system is not functioning C# . NET 4.0

coder 2023-07-12 原文

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

时不时地,串行端口似乎停止响应并抛出 System.IO.IOException: A device attached to the system is not functioning 错误。

这是堆栈跟踪:

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 错误,并且每次软件尝试写入端口时都会出现此错误,并且在我停止之前它永远不会恢复调试并重新启动软件只是为了几天后发生同样的事情。

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

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

我也已经尝试过该论坛上建议的所有遗留错误处理点点滴滴,但它们似乎都没有任何区别。该错误发生在 windows XP Pro SP3 32 位和 Windows7 Pro 32 位上。

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

    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;

    }

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

    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

    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 { }
        }
    }

我现在将重写代码以从同一个线程读取和写入串口,看看是否有任何不同。

编辑

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

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

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

我不喜欢像这样给软件打补丁,但如果它能用,那它也能用。

编辑 2

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

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 次这种情况发生在另一个线程(终止或未终止)没有对硬件端口的独占访问权时。

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

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

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

在上面的代码中,我看到了样式中的消息输出

DebugPrint(ex.Message); 

这样做会更好

DebugPrint(ex.tostring()); 

因为这也会导出异常中的堆栈跟踪。

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

关于c# - 系统.IO.IOException : A device attached to the system is not functioning C# . NET 4.0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18729146/

有关c# - 系统.IO.IOException : A device attached to the system is not functioning C# . NET 4.0的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐