• 3575阅读
  • 13回复

[原创]程序运行一段时间,就异常崩溃 [复制链接]

上一主题 下一主题
离线介农酥
 

只看楼主 倒序阅读 楼主  发表于: 2019-08-17
回复本帖可获得15RMB金钱奖励!
每人最多可获奖2次,奖池剩余15RMB金钱 (中奖几率40%)
程序每次运行一段时间,就异常退出,没有任何提示,要么直接退出,要么弹出异常消息框。


程序主要功能:
1)从4个服务器上分别获取数据AB(每个服务器(TcpServer1秒发送一次数据,4个服务器独立发送,可以同时发,没有时间顺序);
2)根据数据AHTTP的方式获取数据C
3)最后将数据ABC发送给PLC,插入数据库,回传数据给Http
不断从服务器上获取,不断重复后面的步骤。

今天突然想到到调试模式下运行下,发现报错了,代码跳到这个位置,我觉得这是一个很大的提示,截图如下:


错误的地方在GetAdaptersAddresses()

这是又一次调试模式运行下报的错:
Invalid parameter passed to C runtime function(C++
百度知道上有解释:是引用了空或者野指针,之所以会有空指针或者野指针是因为你在另外一个线程把这个指针置空或者释放了,遇到这种情况你需要对这个指针做加锁保护,不然没法解决问题

这是又一次调试模式运行下报的错:不截图了,看红色的地方
void QMYSQLResult::cleanup()
{
    Q_D(QMYSQLResult);
    if (d->result)
        mysql_free_result(d->result);

// must iterate trough leftover result sets from multi-selects or stored procedures
// if this isn't done subsequent queries will fail with "Commands out of sync"
#if MYSQL_VERSION_ID >= 40100
    while (driver() && d->drv_d_func()->mysql && mysql_next_result(d->drv_d_func()->mysql) == 0) {
        MYSQL_RES *res = mysql_store_result(d->drv_d_func()->mysql);
        if (res)
            mysql_free_result(res);  //调试器箭头指向的位置。
    }
#endif
更多的时候调试没有跳到什么地方,感觉每次调试,问题未必一样。不过程序还是照样运行呢,只是弹出报警框,点击确认,程序退出
估计是多线程环境下,内存出了什么问题,但是线程还是要用的,不然性能上跟不上,计算机初级学者,还是希望大家多多帮忙!。真不知道程序哪里写的有bug

写这个程序也是一波三折,我在论坛上也问过其他相关问题。
最开始的时候,我将三个步骤分别放在不同的线程里,并且加了锁,但是运行一段时间解不了锁,之后我将三个步骤全放一个线程里,没有加锁,但是当同时接受4个服务器上的数据时,发现中间有很多次,执行了第一步,第二步,第三步没有执行,或者第二步,返回的字符串“”,如果接受1-3个服务器,我发现是来的及,不会出现什么问题,最后为了解决这个问题,我建立4个线程,每个线程分别独立执行业务流程,即从服务器1上获取数据,然后执行23)步,从服务器2获取数据,执行2)3)步,四个服务器,四个线程,独立完成任务,互不干扰,解决了问题,以为没事了,结果出来这个问题,关键这个问题,我都不知道错在哪,咋调试,如果我只打开一服务器,是没有问题的
前面分几个线程或者放在一个线程里的时候到时没出现过这个问题哦。

好不容易解决了业务和性能上的问题,又出现了这个问题,为什么要如此对我。我现在就是瞎猫看能不能碰上死耗子。


如果还需要提供什么,我可以附件提供,比如源代码。

201908201235 添加

是4个线程,4个线程独立完成任务,每个服务器(摄像机)对应一个线程,C数据是需要根据服务器上的数据(就是摄像头扫的快递号和小车号),从厂家给的接口获取的,这个接口申通的是数据库,比较简单,中通的是http方式,比较麻烦,很慢四五十毫秒,而且是异步的。即这样
服务器A-Http-PLC
服务器B-Http-PLC
服务器C-Http-PLC
服务器D-Http-PLC

Socket4个实例(参数:不同的IP),Http有四个实例,PLC也有4个实例

因为4个socket是独立发数据的,这样可能同时发数据,那么Http就处理不过来了,后面的socket会覆盖前面的。
但是单个socket,一次发数据的间隔有几百毫秒,这样如果一个Http实例只接受一个Socket数据,就能来的及了,而且这样确实也解决了问题。

4个独立线程里面的对象应该都在不同的内存区,但是有些事静态的变量,比如一些配置,因为这些配置对所有的对象来说是一样的,所以我定义成了static。
哦,对了,这些数据都要发给主界面,通过信号和槽的方式,主线程只有一个实例,这算不算共享的存储区。
麻烦,在看看,再提供一些思路

离线小韩老师

只看该作者 1楼 发表于: 2019-08-17
4个tcpserver,软件上应该是4个客户端连接吧,如果是4个客户端则是4个线程。你的单线程和多线程是指如何处理,多线程调试多用打印,你调试打断点时候不知道进的是哪个线程。祝你好运!
在线liulin188

只看该作者 2楼 发表于: 2019-08-17
这种问题只能靠自己了
https://wiki.qt.io/Qt_5.12_Release
https://wiki.qt.io/New_Features_in_Qt_5.12
https://wiki.qt.io/Qt_5.12.0_Known_Issues
https://www.qt.io/blog/qt-5.13.2-released
https://www.qt.io/blog/qt-creator-4.10.2-released
https://wiki.qt.io/Qt_5.12_Tools_and_Versions
离线fsu0413

只看该作者 3楼 发表于: 2019-08-17
回帖奖励+ 10
问题可能出在公有资源竞争上

如果要做到线程物尽其用,要注意:
1. 线程的共享存储空间要少,而且要保证互斥 (两个线程同时取出i=14,同时对i+1,同时放回i,最后i的结果不是想象中的16而是15,需要通过加锁避免)
2. 线程间的等待要少(A等待B,B等待C,C等待D,到最后就D一个在工作,ABC都在浪费资源)
3. 线程间做的事依赖要少(依赖多了就等待了啊)
离线firebolt

只看该作者 4楼 发表于: 2019-08-18
      你这个任务挺简单的,但是设计的复杂了。这种情况不太好帮你找问题所在,归根结底是程序结构设计的问题。网络编程最基本的模式就是生产消费模式,数据采集是生产者,数据处理是消费者。它们可以通过消息队列来通讯。
      结合到你这个程序,数据采集部分会从服务器获取ABC三类数据。其中C数据和A数据是关联数据。采集到这些数据后将他们放到消息队列中由数据处理线程处理,数据处理线程检查消息队列是否有数据,如果有会取出数据根据数据类型做不同的处理。至于消息队列怎么设计你可以查查相关的资料。我这里就不细说了。
离线九重水

只看该作者 5楼 发表于: 2019-08-19
楼主的公司真的是做PLC的吗?
同行?我做过上位机的PLC编译器和下位机的解释器。
离线yunchao630

只看该作者 6楼 发表于: 2019-08-20
回帖奖励+ 10
你这个函数interfaceListing如果是多线程访问的,做一下互斥就好了
离线介农酥

只看该作者 7楼 发表于: 2019-08-20
回 九重水 的帖子
九重水:楼主的公司真的是做PLC的吗?[表情]
同行?我做过上位机的PLC编译器和下位机的解释器。[表情]  (2019-08-19 17:45) 

这么厉害,不是。
离线介农酥

只看该作者 8楼 发表于: 2019-08-20
回 firebolt 的帖子
firebolt:      你这个任务挺简单的,但是设计的复杂了。这种情况不太好帮你找问题所在,归根结底是程序结构设计的问题。网络编程最基本的模式就是生产消费模式,数据采集是生产者,数据处理是消费者。它们可以通过消息队列来通讯。
     .. (2019-08-18 12:57)

是4个线程,4个线程独立完成任务,每个服务器(摄像机)对应一个线程,C数据是需要根据服务器上的数据(就是摄像头扫的快递号和小车号),从厂家给的接口获取的,这个接口申通的是数据库,比较简单,中通的是http方式,比较麻烦,很慢四五十毫秒,而且是异步的。即这样
服务器A-Http-PLC
服务器B-Http-PLC
服务器C-Http-PLC
服务器D-Http-PLC

Socket4个实例(参数:不同的IP),Http有四个实例,PLC也有4个实例

因为4个socket是独立发数据的,这样可能同时发数据,那么Http就处理不过来了,后面的socket会覆盖前面的。
但是单个socket,一次发数据的间隔有几百毫秒,这样如果一个Http实例只接受一个Socket数据,就能来的及了,而且这样确实也解决了问题。

4个独立线程里面的对象应该都在不同的内存区,但是有些事静态的变量,比如一些配置,因为这些配置对所有的对象来说是一样的,所以我定义成了static。

哦,对了,这些数据都要发给主界面,通过信号和槽的方式,主线程只有一个实例,这算不算共享的存储区

麻烦,在看看,在提供一些思路
离线介农酥

只看该作者 9楼 发表于: 2019-08-20
回 小韩老师 的帖子
小韩老师:4个tcpserver,软件上应该是4个客户端连接吧,如果是4个客户端则是4个线程。你的单线程和多线程是指如何处理,多线程调试多用打印,你调试打断点时候不知道进的是哪个线程。祝你好运! (2019-08-17 16:42) 

因为不知道错误,在哪,所以没法打断点,而且它是不断循环运行几千遍,才会出问题,如果打了断点,第一次就停下来了,无法看到错误,谢谢!
离线介农酥

只看该作者 10楼 发表于: 2019-08-20
回 fsu0413 的帖子
fsu0413:问题可能出在公有资源竞争上
如果要做到线程物尽其用,要注意:
1. 线程的共享存储空间要少,而且要保证互斥 (两个线程同时取出i=14,同时对i+1,同时放回i,最后i的结果不是想象中的16而是15,需要通过加锁避免)
2. 线程间的等待要少(A等待B,B等待C,C等待D,到最后就D一个 .. (2019-08-17 20:04)

非常感谢,这里面没有那个线程要等那个,都是独立的,共享的就是一些静态变量吧。其他的每个对象的成员应该都是自己的吧

哦,对了,这些数据都要发给主界面,通过信号和槽的方式,主线程只有一个实例,这算不算共享的存储区
离线yuyu414

只看该作者 11楼 发表于: 2019-08-20
回帖奖励+ 15
如果是代码问题的话就自己慢慢调吧,总能解决。
如果是嵌入式还有个可能就是要设置一些cpu的编译参数,看具体型号版本,不然是会莫名其妙的崩溃的。
离线fsu0413

只看该作者 12楼 发表于: 2019-08-23
回 介农酥 的帖子
回帖奖励+ 15
介农酥:非常感谢,这里面没有那个线程要等那个,都是独立的,共享的就是一些静态变量吧。其他的每个对象的成员应该都是自己的吧
哦,对了,这些数据都要发给主界面,通过信号和槽的方式,主线程只有一个实例,这算不算共享的存储区
(2019-08-20 12:33)

看了一眼你的补充问题。
http有4个实例没问题。QNetworkAccessManager本身就是异步的不用开线程,直接在主线程的消息循环里做就行,这样就没有线程间共有资源竞争的问题了,4个PLC都放在主线程就完事
而且就算用TCP,也可以用异步的信号和信号槽。总之你这个问题,如果数据量不大的话不建议开线程
离线介农酥

只看该作者 13楼 发表于: 2019-08-26
回 fsu0413 的帖子
fsu0413:
看了一眼你的补充问题。
http有4个实例没问题。QNetworkAccessManager本身就是异步的不用开线程,直接在主线程的消息循环里做就行,这样就没有线程间共有资源竞争的问题了,4个PLC都放在主线程就完事
而且就算用TCP,也可以用异步的信号和信号槽。总之你这个问题,如果数据量不大的话不建议开线程


http如果都放在一个线程里的话,同时接受4个摄像头的数据,就会处理不过来,大概是这种情况:不去执行响应的函数或者读取的字符串为空。只有分开才能够好处理。但是你说把它们放到主线程这应该影响不大,因为总体上平均时间还是够的,只是因为4个摄像头发数据的时间是随机的,可能瞬间很大,比如4个同时发,其实你说的异步我也不是很理解,我读取http的响应都是同一个函数,即使异步,只是说http去向http服务器请求数据是异步的,独立的,但是http返回响应的时候总的一个个来吧,总不能4个同时执行一个函数吧。

顺便问下:最开始我还担心数据不同步的问题(http只有一个线程),大致如下:当摄像头1发数据A1和B1给http的时候,http去执行响应的时候,大约50ms左右,这期间摄像头2发数据A2和B2给http的时候,是不是可以把原来的A1和B1给取代?这是否会造成数据不同步(其实我发现同步的问题到没出现)。
如果将http加上QEventLoop,做成的同步的,http所在线程应该还是可以响应其Socket线程(摄像头)的信号吧,这应该仍不能解决同步的问题吧?
所以我突然想,需要再加个锁,QMutexLocker方能真正同步。
快速回复
限100 字节
 
上一个 下一个