简体   繁体   English

C# winforms 冻结:串口、定时器、线程

[英]C# winforms freezing: Serialport, Timer, Thread

Edit: Keeping the original question for continuity.编辑:保持原始问题的连续性。 I then edited the question with replacement code for the ReadLine() method by using ReadExisting instead.然后,我改用 ReadExisting 用 ReadLine() 方法的替换代码编辑了问题。 It works however I still have the same freeze, where the app becomes unresponsive.它可以工作,但是我仍然有同样的冻结,应用程序变得无响应。 Debug says it's locking (it takes a while to freeze, sometimes seconds, sometimes minutes) in the while () {} function where I wait for the complete message. Debug 说它在 while () {} function 中锁定(冻结需要一段时间,有时是几秒钟,有时是几分钟),我在那里等待完整的消息。 More explanations below:更多解释如下:

-- obsolete -- - 过时的 -

What is a good way to handle serialport.readtimeout exception?处理 serialport.readtimeout 异常的好方法是什么?

                    try
                    {
                        serialPort1.Write(Command_);
                        if (!IsWriteComm_)
                        {
                            Response_ = serialPort1.ReadLine().Replace("\r", "");
                        }
                    }
                    catch (TimeoutException err)
                    {
                        DateTime d = DateTime.Now;
                        rtboxDiag.AppendText("\n" + d.ToString("HH:mm:ss") + ": ");
                        rtboxDiag.AppendText(err.Message);
                        if (!serialPort1.IsOpen)
                            InitConnection();
                        return Textbox_;
                    }

this bit of code is exectuted on a timer tick event.这段代码在计时器滴答事件上执行。 I was having a weird "crash" of the app with an IO exception我遇到了一个奇怪的应用程序“崩溃”,出现 IO 异常

"The I/O operation has been aborted because of either a thread exit or an application request." “由于线程退出或应用程序请求,I/O 操作已中止。”

no matter what I do I am not able to "recover" meaning, I am no longer able to poll data from the serial port.无论我做什么,我都无法“恢复”意思,我不再能够从串口轮询数据。

I added this exception catch and it does log the exception.我添加了这个异常捕获,它确实记录了异常。 weirdly enough the test on.serialport.isopen is false (meaning the port is still open).奇怪的是,测试 on.serialport.isopen 是假的(意味着端口仍然打开)。

What might be a hint is: this error does STOP the timer somehow, this is not something I am doing in code.可能是一个提示:这个错误会以某种方式停止计时器,这不是我在代码中做的事情。 so I am suspecting something related to the timer, rather than the serialport, but I could be wrong.所以我怀疑与定时器有关的东西,而不是串口,但我可能是错的。

Closing the port manually, and reconnecting does not fix the problem.手动关闭端口并重新连接并不能解决问题。 Disconnecting and reconnecting the USB does not fix the problem.断开并重新连接 USB 并不能解决问题。

however, closing the app, and relaunching the app does fix the problem (without even disconnecting the MCU or power cycling the MCU/hardware).但是,关闭应用程序并重新启动应用程序确实可以解决问题(甚至无需断开 MCU 或重启 MCU/硬件)。

-- /obsolete -- - /过时的 -

edit: the problem is appearing after a few seconds, sometimes minutes of flawless operations.编辑:问题在几秒钟后出现,有时是几分钟的完美操作。 I cannot repeat the issue using a serialport terminal polling the data the same way, at the same frequency.我不能使用串行端口终端以相同的方式以相同的频率轮询数据来重复该问题。 It seems the problem is not coming from the hardware itself.看来问题不是来自硬件本身。

cheers干杯

Edit: I have yet to test the following modification, not sure if it will fix this problem (I doubt), but at least it's an attempt at not using.readline() which from what I've gathered is not good practice.编辑:我还没有测试以下修改,不确定它是否会解决这个问题(我怀疑),但至少它是不使用.readline() 的尝试,从我收集的信息来看,这不是好的做法。

anyway here it is:无论如何,它是:

                    try
                    {
                        serialPort1.Write(Command_);
                        if (!IsWriteComm_)
                        {
                            while (!SerialRxCplt) ;
                            Response_ = SerialRxResponse.Replace("\r", "").Replace("\n", "");
                            SerialRxCplt = false;
                            //Response_ = serialPort1.ReadLine().Replace("\r", "");
                        }
                    }
                    catch (TimeoutException err)
                    {
                        DateTime d = DateTime.Now;
                        rtboxDiag.AppendText("\n" + d.ToString("HH:mm:ss") + ": ");
                        rtboxDiag.AppendText(err.Message);
                        if (!serialPort1.IsOpen)
                            InitConnection();
                        return Textbox_;
                    }

and I have the datareceived event enabled:我启用了 datareceived 事件:

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            var serialPort = (System.IO.Ports.SerialPort)sender;
            string dataReceived = serialPort.ReadExisting();
            ProcessSerialData(dataReceived);
        }

and this is how I am processing the data, and manually "waiting" for the \n character which tells me when the data has been fully received.这就是我处理数据的方式,并手动“等待” \n 字符,它告诉我何时完全接收到数据。

private void ProcessSerialData(string data)
        {
            SerialRxBuffer += data;
            if (SerialRxBuffer.Contains("\n"))
            {
                SerialRxCplt = true;
                SerialRxResponse = SerialRxBuffer;
                SerialRxBuffer = "";
            }
            else
            {
                SerialRxCplt = false;
            }
        }

any input is welcome.欢迎任何意见。

I have added "stuff" for debugging inside that while loop and it does work fine for a while and then freezes, no error or exception is thrown there.我在那个while循环中添加了用于调试的“东西”,它确实可以正常工作一段时间然后冻结,那里没有抛出错误或异常。 For some reason I have a feeling it's not related to the serial port.出于某种原因,我觉得它与串行端口无关。 I have even added this:我什至添加了这个:

                    try
                    {
                        serialPort1.Write(Command_);
                        if (!IsWriteComm_)
                        {
                            Stopwatch stopWatch = new Stopwatch();
                            stopWatch.Start();
                            while (!SerialRxCplt || Timer2StopWatchMilli > 5)
                            {
                                Timer2StopWatchMilli = stopWatch.Elapsed.TotalMilliseconds;
                                ExceptionMessage = Timer2StopWatchMilli.ToString();
                                IsException = true;
                            }
                            stopWatch.Stop();
                            if (!SerialRxCplt)
                                return Textbox_;
                            Response_ = SerialRxResponse.Replace("\r", "").Replace("\n", "");
                            SerialRxCplt = false;
                            //Response_ = serialPort1.ReadLine().Replace("\r", "");
                        }
                    }

the ExceptionMessage and IsException help me have an idea of what's happening in that loop. ExceptionMessage 和 IsException 帮助我了解该循环中发生了什么。 And in normal operations, it is what you would except, increments in the order of 0.0x milliseconds.在正常操作中,它是您所需要的,以 0.0x 毫秒的数量级递增。 Data is being processed correctly.正在正确处理数据。 When it freezes, nothing looks abnormal.当它冻结时,看起来没有任何异常。 I initially thought I was somehow getting "stuck" in an infinite loop but that ||我最初以为我以某种方式“卡”在无限循环中,但 || Timer2StopWatchMilli > 5 should get me out of it, acting as some sort of timeout. Timer2StopWatchMilli > 5 应该让我摆脱它,充当某种超时。

one extra piece of info: when it freezes, the one CPU core is fully loaded.一条额外的信息:当它冻结时,一个 CPU 内核已满载。 (I have a 6core CPU, and it's 16-17% in the task manager - memory usage is low < 30MB) (我有一个 6 核 CPU,它在任务管理器中是 16-17% - memory 使用率低 < 30MB)

Any help is welcome欢迎任何帮助

I fixed it by clearing RX/TX and stream buffers after each successful transaction.我通过在每次成功交易后清除 RX/TX 和 stream 缓冲区来修复它。 I think data was being sent to the PC faster than it was able to read causing data to eventually accumulating on the Rx Buffer.我认为数据发送到 PC 的速度比它能够读取的速度更快,导致数据最终累积在 Rx 缓冲区中。

private void SerialPortClearBuffers()
        {
            serialPort1.DiscardOutBuffer();
            serialPort1.DiscardInBuffer();
            serialPort1.BaseStream.Flush();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM