记录一个单线程调用写出现的"死锁"问题

本文记录了一个在单线程环境下,pthread_mutex_t互斥锁在lock时出现死锁的问题。问题的根源并非传统的死锁原因,而是由于调用程序和被调用程序头文件不一致导致的内存破坏。解决方法包括使用智能指针进行更松耦合的系统集成,以及在类成员使用中避免直接包含其他类对象,推荐使用接口指针。此外,还探讨了智能指针unique_ptr和shared_ptr的使用场景及注意事项。
摘要由CSDN通过智能技术生成

问题的现象是出现一个pthread_mutex_t 互斥锁在init成功后, 在 pthread_mutex_lock 的时候出现死锁, 然后程序卡住一直执行不下去, 但是调用的地方只有在一个线程中, 没有多线程同时调用pthread_mutex_lock的情况 ;

这种情况下, 调查一般死锁的思路是完全没用的,而且会怀疑人生,所以必须要像寒战里刘杰辉破案一样, 要更宏观的去找原因,O(∩_∩)O哈哈~; 发现这个问题时,当时用的是打印 pthread_mutex_t 的 __data.__ownwer成员发现是一个很大的数,完全不像一个线程id;

这种"神奇"的bug现象下,rootcause完全跟线程,互斥所没有一点毛的关系, 而真正的原因是调用程序和被调用程序使用的头文件不一致而造成的内存破坏, 更确切的举例说, 比如, 被调用方的的一个C++类的的定义改变了,增加,删除或修改了几个成员, 但是成员函数接口都没有变, 而只是数据成员变了,并且成员函数内部实现变了; 这时候,如果调用这个类的代码跟这个类的实现不在一个库中, 也就是分别编译的, 那么如果只更新编译了被调用方, 而不使用新的头文件重新编译调用方的话, 整个程序执行就可能有问题; 

因为在这个例子中,调用方直接使用被调用的那个类的对象变量作为自己类的成员变量, 而不是使用的被调用类的指针作为自己类的数据成员, 在这个例子中,就看出了指针使用的好处; 直接使用类对象的情况下,相当于自己类的内存布局中包含了调用类的内存, 而当上述头文件不一致的情况发生时, 在运行时,自己的类内存的布局还是原来旧的布局, 而被调用类的库已经更新了,这时候被调用类的库的执行代码会按新的内存布局来访问现在的调用类的内存中的被调类内存,显然会写出错,于是造成各种很奇怪的问题,最终原因都是头文件不一致导致的内存破坏;这种问题经常发现在系统集成的测试中,一般单独的测试不太容易测到; 一个号称自己擅长系统集成的人或公司,应该对这种问题特别了解;

那么从编程和系统集成的角度扩展开来时, 两个类存在包含关系时, 最好不要用类对象直接作为成员变量, 做好用指针+interface的方式, 可以配合上只能指针等形式, 这样, 能够保证调用类的内存不会被被调用类的内存而影响; 因为被调用类的内存的分配就和此时调用类的构造和初始化分配是分开的; 从而这种集成是更松耦合的; 从原理上,指针这种类型的使用, 也是从系统角度去管理内存,因为指针实际指向的内存情况由系统来负责, 把更多的事情交给能够在第一时间发现任何组件变化的系统来做, 才是更符合系统集成的思路, 才能更容易发现和解决问题,而且也才是更鲁棒的系统集成方式;

智能指针使用的一些总结;

默认的智能指针应该是unique_ptrunique_ptr意味着所有权。单个unique_ptr离开作用域时,会立即释放底层内存, 只有需要共享资源时,才使用shared_ptr。 最后一个shared_ptr离开作用域时,才会释放这块内存;

数据只有两种: 数组和非数组:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值