解决程序无响应

最近在解决一个程序无响应的问题上面花了不少时间,总算是找到了原因,下面简单记录一下查找的过程。
        
        先说一下场景:A程序为windows 桌面应用程序,界面基于QT,B程序为C#程序,在B中使用了windows自带的MSAA服务的IAccessible来操作A的一些界面功能。在操作过程中出现A,B进程同时无响应。A代码庞大,并且出现无响应的概率不大,无法直接进行调试。

        对于一般的程序无响应,首先想到的应该就是是否有死循环,这个直接通过任务管理器的CPU占用就可以判断,CPU没有占满,那么就可以直接排除;另外就是死锁,对于一般的死锁,可以打开任务管理器 -> 性能 -> 资源监视器来查看无响应程序的线程等待链,通过线程等待链找到相互等待的线程,获取堆栈分析原因。

        在我的程序出现问题时,按以上原因逐项查看。。。什么? 没有死循环,也没有线程等待链,这。。。再检查一遍,还是没有!!!没办法,只能attach调试,发现等待发生在QMetaObject的addGuard中,在addGuard中确实用了QMutexLocker,但是怎么会没有线程等待呢,想了很久无果后才查看了QMutexLocker的实现,这东西竟然使用的是Event实现的,恍然大悟,终于知道了为什么以上方法都不对:对于一般的Mutex来说,他是有归属的,而对于Event来说,没有归属,Event在wait后,其他任何地方都可以通过reset来使他恢复,所以就不会有等待链。

        分析了addGuard的代码,他只是一个很简单的操作,并且也是QT自己内部使用,应该不会出现常规的一些问题,初步估计可能出现在其他线程访问时刚好线程出现异常或线程终止,于是添加了hook函数来监测TerminateThread的调用情况,未发现异常。AB程序同事无响应,那么很有可能是在AB之间通信时出现了某种问题导致卡住。查阅COM相关介绍及MSAA,了解到在系统自带的COM组件中,一般都会在最外层做try catch来捕获调用时出现的异常,从这里可以想到很有可能出现在B调用COM时,COM在回调A程序时,发生异常,而这种异常刚好被异常捕获处理,未发生崩溃,A程序未能调用reset,导致B程序也无法等到回应,两个程序卡住。

        到这里,可以添加部分代码来验证猜测了。于是对COM回调的A程序的代码全部加异常捕获,看看执行时是否会出现exception,经验证,确实出现了,查看出现的位置原因,发现出现时一个QPointer对象,他的指针存在,但是内部数据都没有了,QPointer在说明中他是会在对象删除时自动删除引用的,唯一可能出现的原因应该就是在多线程里面删除导致QPointer也没有正确记录,对客户端编程来说,UI对象在非UI线程操作都可能导致严重的问题,在JAVA里面已经明确限定这一点,如果存在非UI线程操作UI对象,将直接报错,而C++不做任何处理,导致了给部分人犯错的可能。

    接下来要做的就是对我们使用的UI对象在他的析构函数里面加检测,判断他的删除操作是否在UI线程中,不在UI线程中直接使程序崩溃,记录堆栈。我是直接修改了QT的QWidget,用修改过后的QT来跑之前的操作,从程序的崩溃中就可以直接看出什么地方做了不该做的事。

你可能感兴趣的:(QT)