越是诡异的错误,原因越是白痴

有点编程经验的人应该都深有体会,一般这种情况最容易发生在刚学编程不久的人身上,经常一个诡异的编译错误导致一个美好的周末付诸东流,经过千万次的自我否定和质疑——自己是不是选错了职业,才终于发现一个遗失的大括号正朝自己微笑,或者一个正巧同变量函数名同名的宏正在墙角冷笑。

 

如果你以为我这篇文章是要谈编译错误,那你就错了。好歹这么多年的老鸟,就算遇到诡异的编译错误也不能承认啊,丢不起那人。最近遇到的是一个单看描述相。。。。当诡异的问题,公司的程序,启动的时候就挂在那里了,用gdb查看,是卡在一个第三方库的事件类里面,卡在哪一行也很清楚。pthread_mutex_lock(&_mutex)。 按说这种问题很容易解决,不能对这个_mutex加锁。肯定就是这个_mutex已经被锁过了。但是问题就在于程序是卡在框架启动的一开始,一共就一个线程。所以不可能有其他线程对这个mutex加锁。

 

那就还剩下一种可能,这个_mutex不是recursive的。已经被加过一次。所以不能再加。但是经过查看代码,打印日志,设置断点这三板斧后,发现这个mutex一共就锁这一次。而且这部分代码是框架代码,其他使用这个框架的程序都是一路畅通,就这一个会卡住。而且如果我把第三方库的那个事件类的源代码拷贝出来,重命名为另一个类,替换掉正在使用的这个事件类,也会一路畅通。也就是说同样的代码,放在第三方库里就会有问题,拿出来就没有。

这个时候就有点抓狂,然后就开始胡思乱想,于是认为是不是库的链接出了错误,某个库在链接的时候很神秘地侵占了另一个库的空间或者代码,花了大概一个小时的时间在那里调换各种库的装载顺序,结果这个问题没解决,还把静态全局变量初始化这个问题给放出来了。

 

于是只能重新回到gdb里面一步步调试,_mutex是个union。里面有个成员变量叫__lock的用来保存被lock的次数。一开始的pthread_mutex_init没有任何问题。__lock的值为0,但在调用pthread_mutex_lock(&_mutex)的时候__lock的值就很诡异地变成了2.经过查看_mutex的地址,发现pthread_mutex_init里面的_mutex地址比pthread_mutex_lock的地址多了两位。

 

事件类的成员变量如下。按照默认的字节对齐。假设起始地址为0,_mutex的地址应该为4。从gdb结果来看pthread_mutex_init的时候_mutex的地址为4,但是pthread_mutex_lock的地址为2. 也就是说在呼叫pthread_mutex_lock的时候,_mutex的地址发生了改变。这样__lock的值自然也变了,导致无法加锁。

 bool            _auto;
 volatile bool   _state;
 pthread_mutex_t _mutex;
 pthread_cond_t  _cond;

 

_mutex的值为什么要为2呢,最大可能就是1字节对齐。这个时候我才想到我在一个头文件里对某些结构体加了#pragma pack(1)这个语句强制这些结构体一字节对齐。很有可能我忘记关闭1字节对齐了,当时真的是颤抖着打开那个文件,心里默念一定要是这个原因,结果还真是漏掉了在那些结构体后面#pragma pack()这句关闭1字节对齐的语句。加上之后,重新编译,程序很顺溜地过了。

 

问题是解决了,原因也很小白,忘记关闭字节对齐。但是随之而来的又是很多其他问题,忘记关闭1字节对齐为什么会影响到pthread_mutex_lock。却不会影响到pthread_mutex_init。这两个函数相距不远,几乎就是调用完一个,很快就是第二个。还有就是这个事件类是第三方库,早就已经编译好,为什么还会受这个1字节对齐影响?还有。。。。

 

解决一个疑问总是导致更多的疑问,我是不是选错职业了。。。。。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值