又犯了低级错误——这次是 vector

下午大部分时间都在调一段 c++ 代码。某线程共享 vector,用于存放对象的指针。创建对象之前先要检查一下是否已经存在符合某条件的对象,有则取消创建。对象创建时指针进入 vector,对象销毁时指针从 vector 中删除。

逻辑虽然简单,但是因为需要线程安全,所以加锁解锁也是步步小心。

但是跑起来之后还是出了问题。有时候明明 vector 应该已经空了,检查函数竟然返回存在的结果,导致某该被创建的对象创建失败。

根据日志输出,进行这个对象的创建前检查正巧位于某线程将某对象刚刚从 vector 中删除的时候,而检查出已存在的结果恰好是那个刚刚被删掉的指针,于是本能的怀疑是线程同步出了问题。

集中精神,走查代码(注意力都在加解锁上,这个过程耗时比较长)。一无所获。无奈,在日志输出中将每次 vector 操作时 vector 的状态进行了详细输出 。

令人瞠目的一幕出现了,vector 的 size 居然就从没有减少过!

赶紧检查 destructor,是这样写的:

...
LockMutex(...)
remove(foo_vector.begin(), foo_vector.end(), this);
UnlockMutex(...)
...


如果你也看不出不对,那么恭喜,你的 c++ 水平和我一样不济。不用多解释,看文档,好好补习一下 remove 到底是怎么用的。这个地方用 remove 其实并不合适。

将上述代码改成如下形式,问题解决。

...
LockMutex(...)
vector::iterator it=find(foo_vector.begin(), foo_vector.end(), this);
if (it != foo_vector.end())
foo_vector.erase(it);
UnlockMutex(...)
...


感受:
1、此例跟多线程一点关系也没有。“程序员的第一直觉几乎总是错的”说的就是这个。
2、“用非母语交谈,思维易受干扰”,用不熟悉的语言编程,也是一样。
3、不折不扣的 printf debug 流。
4、c++ 还是半吊子。
发表评论