关于多线程操作同步对象造成死锁的解决方式(二)

      上篇文字介绍到如果有效避免死锁的发生,那么这篇文件将介绍当死锁发生时我们如何知道并能够得知死锁发生的情形,然后快速解决它。 那么这篇文章主要讲解原理性东西不会贴很多代码,下面进入正题。

      在上篇文件定义了自动锁安全类后,我们看到有些函数进行了重载,其中参数有文件名,函数名,代码行等参数,那么这个信息就是帮助我们定位死锁时代码执行到哪个位置的信息,那么我们如何传入这些参数呢?我们可以用宏来解决这些参数问题,宏定义如下:

//! 使用以下宏时,发生死锁时可以快速完成死锁代码调用栈的输出
#define SafetyAutoLockEx(csLock)		SafetyAutoLock al##_csLock(&csLock, __FILE__, __FUNCTION__, __LINE__)
#define SafetyAutoLockResetEx(csLock)   al##_csLock.Reset(&csLock, __FILE__, __FUNCTION__, __LINE__)

        我们只需要传入临界区对象即可,宏自动帮助我们创建一个安全自动锁对象,并且传入调用本宏时的代码文件,函数,代码行等信息,一句代码搞定。既然我们能得带每个临界区在进行锁代码操作时候具体位置信息那么我们也就可以将其保存起来,然后在对象析构时移除刚才保存的信息,当有死锁发生时那么我们就可以将保存信息输出到一个log文件中进行分析,然后得知具体代码位置。

        我们保存信息的时候还得考虑一些问题,比如我这个临界区对象的操作是在哪个线程调用的,因为只有多线程时才会出现死锁的现象,那么我们要将保存的信息跟线程相关联起来。保存的信息用什么数据结构保存呢?最好的方案当然是使用Stack来保存这些调用信息,这样就跟我们函数调用栈保持一致了。保存文件时我们通过逐个线程逐个调用栈进行输出,这样日志文件中就能很好的体现当前线程的正在执行的临界区对象,当发现临界区对象有交叉使用等情况时就可以很快速的得知死锁的发生原因了,其他的情况只需要稍微分析下也能很快得知死锁发生的问题所在。我们在什么时候进行保存这个日志文件呢?首先我们得创建一个监控线程,一直监控我们保存的调用信息栈,当发现某个线程的某个调用信息记录的时间和当前时间超过我们设置的阈值时,就将文件输出,并提示出来。

        这个方案使用的地方可以是软件发布之前的测试阶段,测试的时候如果出现死锁问题,我们只需要拷贝日志文件即可,当软件稳定发布后即可关闭此套系统,因为这个方案毕竟还是有点性能损耗的(测试平台为wince,PC平台基本可以忽略性能问题)。

         当然此方案也不止监控临界区也可以监控其他函数的执行,因为一个大系统中可能有第三方Api我们需要调用,有时候这些Api出现问题可能会一直阻塞在里面不返回,那么我们在怀疑这个Api是否有可能阻塞不返回时可以采用上面的形式加入调用栈信息即可。

         方案源码下载地址(方案中使用的存储方式是采用List未采用上述中的Stack,因为某些原因所以取消了stack方式):http://download.csdn.net/detail/flyound/4822457,如果有任何问题欢迎指正。

你可能感兴趣的:(wince,windows,C/C++)