一个让我怀疑信仰的BUG——关于临界区

来源:互联网 发布:怎么在淘宝上找批发店 编辑:程序博客网 时间:2024/05/28 05:17

    最近,调程序时偶然发现一个纠结的问题,关于临界区的。临界区是一个容易出问题的东西,但是大部分都是死锁,而我却出现了另外一个问题,受临界区保护的临界资源访问发生了不一致!
    一开始我的直觉是肯定是临界区的代码没有处理好,某个地方临界区的进入和退出没配对,不是只退没进,就是进一退多。于是乎我仔细的检查了所有访问临界资源的地方,都是严格的受到临界区的保护,而且进入和退出计数都是一致的啊。后来发现,一个线程正在受临界区保护的代码中访问临界资源,但是另外一个线程也进来了!
    这个问题让我纠结了,两个线程同时Enter同一个临界区,怎么可能都进来呢?由于我的这个临界资源访问相当频繁,但是出现这个问题的频率却很低,所以我还是认为肯定是代码的逻辑有问题,在某个特殊情况下临界区出现了不一致。于是乎将访问临界资源的代码重整了一下,尽量保证临界区中的代码简单明了。后来我自己都感觉这么几行代码不可能再出什么不一致问题了。测试发现这个问题好像没有了。
    过了几天偶然间发现这个问题又来了!纠结了,仔细看了看很少的几行代码,怎么也看不出什么问题。我对自己的代码诊断能力还是比较自信的,这几段代码不可能出问题啊!于是乎我开始出现幻觉了,微软的问题?Gflags的问题?360的问题?
    实在没有办法,就这样纠结了两天,一无所获。
    后来我发现了程序的另外一个问题,也是有点纠结,语音朗读时偶然出现"计划外"的终止朗读的情况,找了很多地方,很多种可能就修复了(这也算点好处,呵呵),但是问题依旧。后来偶然发现两段朗读文本释放的是同一个事件对象!怎么出现这种情况?后来发现,系统对事件对象分配的句柄是连续的(应该就是某个内核对象数组的索引吧),由于一段文本朗读使用的事件对象虽然已经关闭了,但是朗读线程仍然可能会再次置位它(朗读和控制是异步的,由于给一个失效的事件置位影响不大,所以就没有检测事件有效性,其实检测了也没用,呵呵)。这样,下一次朗读文本时分配的事件和这个事件的句柄一样,如果朗读线程延迟,朗读线程置位的就是新的朗读文本,使得它认为文本朗读完毕了!这样就造成了"计划外"的终止朗读的情况!
    找到问题的原因就好解决了,只需要保证朗读的终止严格同步即可。问题随即解决。
    突然联想到那个临界区的问题是不是也和这个有关?恍然大悟,确实有关!临界区用的也是事件来实现互斥的啊!如果两个线程同时尝试Enter临界区,那么一个线程肯定会阻塞,这是毋庸置疑的。但是如果朗读线程神经病似的给这个临界区的互斥事件置位会如何呢?那这个阻塞的线程当然会进入临界区了,于是乎也就产生了两个线程同时进入临界区的现象!正常情况下阻塞的线程也是这样进入临界区的,只是此时给这个互斥事件置位的是进入临界区的那个线程Leave临界区时系统完成的。
    至此,两个问题同时解决,一石二鸟,重新找回了信仰。

原创粉丝点击