最近在用Qt写一个windows平台下的客户端项目,运行程序的时候发现,程序运行一段时间后会自动死掉,然后报错“XXX.exe 中的 0x6510af2d (QtGuid4.dll) 处未处理的异常: 0xC0000005: 读取位置 0xdddddde9 时发生访问冲突”或者“XXX.exe 中的 0x6510422c (QtGuid4.dll) 处未处理的异常: 0xC0000005: 读取位置 0xdddddde5 时发生访问冲突”。其中“XXX.exe”是我正在运行的客户端项目可执行文件的名称。
经过反复测试,我发现该bug在程序运行过程中出现的时间是随机的,也就是程序可能运行2分钟出现这个bug,也可能半个小时才会出现这个bug,但只要出现这个bug,程序就会死掉。程序死掉的位置也是随机的,有时候会死在qregion.cpp中的函数isEmptyHelper(const QRegionPrivate *preg)中,有时候会死在qregion.cpp中的函数isEmpty()中,有时候会死在qvector.h中的函数size()中,还有时候会死在qvector.h中的函数realloc(int asize, int aalloc)中。总之程序死掉的时间跟位置都是随机的。
经过在网络上搜索该问题,网络上称该问题产生的原因大概有两种:指针未初始化或数组越界。但我仔细检查程序后发现应该是没有这些问题的。
经过长时间的调试,终于找到导致该bug的原因:在子线程里面执行了GUI操作。由于该项目是客户端项目,后端开发人员把“服务器上报数据给客户端”的操作封装成回调函数给我使用,而这些回调函数是以dll的形式做成接口给我的,所以我不知道里面的实现是怎样。后来跟后端开发人员沟通,才知道原来他给我的这些函数是开启了子线程的,而我在这些函数里面接收了服务器上报的数据后, 又在这些函数里面马上更新了GUI界面,所以才导致了这个bug。
总结:
1:不要在非GUI线程里面执行GUI操作。在子线程里面执行GUI操作可能会导致程序死掉,可能也不会死掉,这就是我上述说的“经过反复测试,我发现该bug在程序运行过程中出现的时间是随机的”的原因。但是一定要避免在子线程里面执行GUI操作。可以在子线程中通过信号与槽,或者状态变量,通知主线程更新GUI。
2:作为客户端开发人员一定要具有后端和服务器的知识,不能只会调用后端开发人员提供的接口。当有了这些知识后,才能更好地找到bug,或者站在整个系统的层面上去设计软件。