vector在多线程下的问题

      程序出现了coredump,用gdb发现了出错的地方。

vector<size_t> seq_offset;
......
if(seq_id < seq_offset.size())
{
    seq_offset[seq_id];        //此处coredump
}

      没有超过vector的大小,访问是不应该有问题的,而且这一现象是偶然出现,所以怀疑是多线程的原因。果然在另一个线程里发现对seq_offset有 insert操作,insert本身不会影响访问,但是当vector大小不够的时候,insert会引发内存重新分配。STL代码(linux gcc-3.4.3 /usr/include/c++/3.4.3/bits)里,vector的insert会调用_M_fill_insert,而当空间不够时 _M_fill_insert会重新分配空间,并将相关数据结构指向新空间。

文件 vector.tcc
324        std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish);        //销毁vector里的元素,即调用各元素的析构函数
325         _M_deallocate(this->_M_impl._M_start,                                           //收回存放各元素的空间,即free
326               this->_M_impl._M_end_of_storage - this->_M_impl._M_start);       
327         this->_M_impl._M_start = __new_start.base();                                //数据结构指向新的空间
328         this->_M_impl._M_finish = __new_finish.base();             
329         this->_M_impl._M_end_of_storage = __new_start.base() + __len;

      麻烦就在于当326行结束后,_M_start指向的是一块已经释放了的空间,这时候再有vector的访问操作(如 seq_offset[seq_id])当然就会coredump。其实STL完全可以先把_M_start赋给一个临时变量,然后_M_start指向 新空间,最后再释放临时变量指向的空间,这样可以保证在多线程下顺利运行。不过STL文档说了——它不支持多线程——所以这样做也没错。
      加锁也可以解决这个问题,不过那样太低效了,不予考虑。最后的解决方案是,用vector的reserve方法预先分配好内存,免得在使用中动态增长。


相关文章

分类

1 Comments

阿洒 said:

感谢楼主的分析,最近做的项目也遇到了这个问题,跟楼主是一模一样的问题,在网上找了挺多原因的,看了楼主的分析才恍然大悟。最后采用了预先分配好vector大小,并保持不变的方法,解决了问题。 幸好该项目中vector的大小还是可以预先知道的,虽然多加了些代码,但是效率明显是提高了。

留言:

关于文章

This page contains a single entry by DongHao published on 10 24, 2008 2:24 PM.

植物兄弟 was the previous entry in this blog.

Dynamo学习 is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.