互斥锁使用不当导致线程阻塞

写作目的

多线程之间通过消息队列进行进程间通信,在线程内部互斥锁使用不当,导致线程阻塞。花费了比较多的时间去定位,故整理下自己所犯的错误,也为后来阅读者起一个提示作用,加强自己对锁的认识与理解。

错误示例

本文讲述的互斥锁,关于互斥锁的创建、加锁、解锁和互斥锁的删除这里就不做详细的介绍。

该错误示例:A线程和B线程通过消息队列实现线程间通信,A线程接收到B线程的数据后,会加锁进行处理,处理完成后,再解锁。本来这个流程是没有问题。后来新增需求,直接移植了一个函数C,该函数内部也进行了加锁处理,该锁和A线程的锁相同,所以B线程发送新的消息给A的时候,B加锁后,调用C进行处理的时候,C也进行了加锁,但是因为锁已经lock了,导致B线程阻塞了,从而导致整个进程的异常,如socket链接断开、程序无响应等。

问题引入过程

起因:一个新的需求,要求导出日志文件。
因为B线程负责的就是日志模块,对于这个新的需求,第一反应就是在该模块实现该功能函数C,对于该功能的实现,涉及操作全局变量,故进行了加锁保护。自测试导出功能没有问题。

  1. 因为A线程负责接收UI发送的消息,收到导出日志的消息,A线程直接调用C函数,自测试OK。于是提交了代码。
    代码审批意见:不同线程之间不能直接调用函数,增加了模块之间的耦合性,不利于模块的维护,建议使用回调处理。

  2. 于是改用回调函数的方式实现,自测是OK,于是又提交了代码。这个时间很快。
    代码审批意见:因为A线程负责接收UI发送的消息,需要快速处理,而导出日志这个函数的时间不能确定的,和日志的大小有关系,可能会导致线程阻塞一会,影响A线程对其他UI消息的处理,建议将C函数放到B线程中进行处理。

  3. 于是想到A线程发送一个消息给B线程,B线程收到A线程发送的消息后,就调用C函数实现日志导出功能。于是就开始coding代码,coding完成后,就进行自测试,发现功能不正常,而且整个进程都不正常,socket链接中断……于是就开始梳理整个流程、增加日志定位,最后才发现是C函数加锁一直等不到资源,阻塞住了

解决办法

解决方法去掉函数C中的加锁和解锁,统一在B线程的任务函数中进行加锁处理,B线程任务函数所有调用的函数不得进行加锁与解锁操作,由B线程任务函数统一控制。

总结

就是因为互斥锁使用的不当,重复加锁,导致线程阻塞,足足花费了4个小时的时间去定位问题,对自己来说,算是自己给自己挖了一个坑。以后对用到互斥锁的地方一定要看上下文环境,避免此类问题的出现。

你可能感兴趣的:(Linux多线程编程)