看不见的错误,应用程序卡住 [英] Unseen bug, application stucks

查看:80
本文介绍了看不见的错误,应用程序卡住的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序已完成约95%,现在我处于测试阶段.
我在debug文件夹中使用了.exe文件,然后使用该应用程序保存了来自gps模块的字符串突发中的特定行,以访问数据库. 这是流程

My app is about 95% completed and now I am on a testing phase..
I used the .exe file in debug folder then I use the app to save a specific line from a burst of string from a gps module to access database..
Here's the flow

样本数据

从gprmc到gpgsa = 1秒间隔.因此,从技术上讲,模块每秒发送三行左右.

Sample Data

from gprmc to gpgsa = 1second interval. So technically module sends three lines or so every second.

Try  
Dim fruit As String = "$GPRMC"

            For Each line As String In RichTextBox1.Lines
                If line.Contains(fruit) Then
                    ProgressBar1.Value = 0
                    txt = line.Split(","c)
                    Insert()
                End If
            Next
Catch ex As Exception
        sPort.Close()
        MessageBox.Show("There had been no data received.", Me.Text, MessageBoxButtons.RetryCancel)
        Call btnStartTimer_Click(sender, New EventArgs)
    End Try

Minute_Tick下,每60秒Second.Start(上面的代码是 ).每分钟,我清除RichTextBox,然后2秒钟(再次填充rtb)后,得到其中包含$GPRMC的行,并将其.Split存入数组〜txt().从今以后,我将单词用逗号分隔成一个数组.

Under Minute_Tick, every 60sec, Second.Start (which is the above code). Every minute, I clear the RichTextBox then after a 2 seconds (rtb is filled again) I get the line with $GPRMC in it and .Split it to an array ~ txt(). Henceforth I have the words separated by coma in an array.

现在,我将其添加到数据库中:

' Now inside a Using block
           If txt(3) = String.Empty Then
                .AddWithValue("@lat", 0)
            Else
                Dim la As Double = Double.Parse(txt(3).Substring(0, 2)) + Double.Parse(txt(3).Substring(2)) / 60.0
                .AddWithValue("@lat", la)
            End If

txt(3)是Latitude DMS格式,因此我添加了一些转换代码段.效果很好,尽管我添加了一个条件以确保不会为null或0值进行计算.

txt(3) is the Latitude DMS format, so I added a little converting snippet. It works fine, though I added a condition to make sure it will not compute for a null or 0 value.

更新(我不能真正理解这段代码,因为我只是复制了它,但是它与我创建的最后一个应用程序都可以正常工作.)

UPDATE (I can't really understand this code, because I just copied it, but it works fine with the last app I created.)

Delegate Sub SetTextCallback(ByVal [text] As String)
Dim x As New SetTextCallback(AddressOf ReceivedText)
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles sPort.DataReceived
    ReceivedText(sPort.ReadExisting)
End Sub
Private Sub ReceivedText(ByVal [text] As String)
    If Me.RichTextBox1.InvokeRequired Then
        Me.Invoke(x, New Object() {(text)})
    Else
        Me.RichTextBox1.Text &= [text]
    End If
End Sub


我发现的问题
我遇到了类似线程睡眠"的问题.该应用程序挂起,无法单击,无法关闭,但是它在任务管理器上运行",所以我认为它处于无限循环中,还是我错了?我结束了在任务管理器上关闭它,然后再次打开它.运行顺利..然后稍后它将卡住.
我一直在想,直到现在,是什么原因造成的?我以为是因为模块不能总是得到信号,所以它什么也不返回..但是,如果模块没有给出坐标,它会在DB (上面的代码)中保存0,所以没有问题那.


Troubles I found
I am experiencing something like a Threading Sleep. The app hangs, can't click, can't close, but its "running" on the task manager, so I think it is in an infinite loop, or am I wrong? I ended closing it on task manager, and open it again. Runs smooth.. then later, it will stuck.
I was thinking and until now, what causes it? I thought its because the module cannot always get a signal, so it returns nothing.. but it saves 0 in the DB (code above) if the module did not gave coordinates, so there is no problem in that.

你们能帮我这个罪魁祸首吗?我是第三天,所以我决定需要一些帮助.谢谢.让我知道您是否需要任何说明.

Can you guys help me the culprit? I am on my third day so I decided that I need some help. thanks. Let me know if you need anything or some clarifications.

推荐答案

If Me.RichTextBox1.InvokeRequired Then
    Me.Invoke(x, New Object() {(text)})
Else
    Me.RichTextBox1.Text &= [text]
End If

您的代码正在执行此操作:

Your code is doing this:

这是一个 firehose 问题.该问题始于SerialPort.ReadExisting()调用.通常返回一个或两个字符,串行端口非常慢.在普通波特率设置为9600波特的情况下,您每秒可获得1000个字符,因此您可以以每秒约500次的速度有效地向RichTextBox中添加新文本.

This is a firehose problem. The issue started with the SerialPort.ReadExisting() call. That normally returns one or two characters, serial ports are pretty slow. At a common Baudrate setting of 9600 baud, you get 1000 characters per second so you effectively add new text to the RichTextBox about 500 times per second, give or take.

这将强制RichTextBox重新分配其内部缓冲区,该缓冲区存储文本并为多余的添加字符腾出空间,然后将所有现有文本从旧缓冲区复制到新缓冲区中并追加新文本.然后更新屏幕.

This forces the RichTextBox to re-allocate its internal buffer that stores the text and make room for the extra added characters, then copy all of the existing text from the old buffer into the new buffer and append the new text. Then update the screen.

这在您第一次启动程序时非常顺利,RichTextBox尚不包含太多文本.但是越来越昂贵,必须复制越来越多的字符.

This goes pretty smoothly when you first start your program, the RichTextBox doesn't contain much text yet. But gets progressively more expensive, more and more characters have to be copied.

直到达到临界点,复制开始会花太多时间,比调用Me.Invoke()的时间还长. UI线程现在开始落后,无法跟上.就像尝试从消防水带喝水一样.复制完内部缓冲区后,还需要分派另一个调用请求,以强制重新分配缓冲区.

Until you reach a critical point where the copying starts to take too much time, more time than the rate at which you call Me.Invoke(). The UI thread now starts to fall behind, never being able to keep up. Like trying to drink from a fire-hose. As soon as it is done copying the internal buffer, yet another invoke request needs to be dispatched, forcing the buffer to be reallocated again.

UI线程现在停止执行其正常的低优先级任务.其中包括更新屏幕和处理输入事件.您从冻结的程序中注意到了这一点,好像它已经死锁了一样. Windows将您的主窗口替换为显示无响应"的幻影窗口,并且在鼠标或键盘上敲击均无效.您所能做的就是用调试器或任务管理器终止程序,然后重新启动它.效果很好,RichTextBox再次具有空缓冲区,并且复制又便宜了.

The UI thread now stops taking care of its normal lower-priority duties. Which includes updating the screen and handling input events. You notice this from your program acting frozen, as though it has deadlocked. Windows replaces your main window with the ghost window that says "Not responding" and banging on the mouse or keyboard has no effect. All you can do is terminate the program with the debugger or Task Manager and restart it. Which works fine, the RichTextBox again has an empty buffer and copying is cheap again.

请注意在处理字符串时这是一个普遍问题. .NET Framework具有 StringBuilder 类可以解决该问题.但是该功能不适用于RichTextBox,您需要找到其他解决方案.

Do note how this is a general problem when handling strings. The .NET Framework has the StringBuilder class to solve it. That however isn't available for RichTextBox, you need to find a different solution.

因此您可以大约每秒500次有效地向RichTextBox中添加新文本

so you effectively add new text to the RichTextBox about 500 times per second

您需要解决那个问题.以这种速率向RTB添加文本是没有意义的,没有人能观察到如此高的速率.每秒添加20次文本已经足够快,如果您这样做的速度更快,它就会开始看起来像模糊.换句话说,现在您的处理速度比需要的快25倍.让实时出价工具和用户界面线程很难跟上该速度.

You need to tackle that problem. It is pointless to add text to the RTB at that rate, no human can ever observe such a high rate. Adding text 20 times per second is already plenty fast enough, it starts to look like a blur when you do it faster than that. Or in other words, right now you doing it 25x faster than necessary. Giving both the RTB and the UI thread a hard time keeping up with that rate.

还请注意,这解释了您的解析问题.您正在解析文本的不完整行.因此,对此的一阶解决方法是仅在从串行端口获得完整的文本行时才调用.这很容易实现:

Also note that this explain your parsing problem. You are parsing an incomplete line of text. So a first-order fix for this is to only invoke when you get a complete line of text from the serial port. That's very easy to come by:

Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles sPort.DataReceived
    ReceivedText(sPort.ReadLine)
End Sub

换句话说,您要求串行端口返回整行文本,而不是返回一个或两个字符.这会自动大大降低调用率并解决您的解析问题.

In other words, you ask the serial port to return an entire line of text instead of just one or two characters. This automatically greatly lowers the invoke rate and solves your parsing problem.

您还需要做两件事.当您的程序运行足够长时间时,它仍然会挂起.您确实必须限制RTB中的文本量.当它存储了超过65000个字符时,只需将其丢弃一半即可.而且您必须删除对Close()方法的调用,这将导致真正的死锁,因为如果DataReceived调用仍停留在ReadLine()调用中,则无法关闭端口.一定要使用BeginInvoke()而不是Invoke(),这样可以减少死锁的可能性.

Two more thing you have to do. Your program will still hang when it runs long enough. You really do have to limit the amount of text in the RTB. Just throw half of it away when it stores more than, say, 65000 characters. And you have to remove the calls to the Close() method, that's going to cause real deadlock because the port can't be closed if the DataReceived call is still stuck in the ReadLine() call. Do use BeginInvoke() instead of Invoke(), less danger of deadlock that way.

这篇关于看不见的错误,应用程序卡住的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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