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方法预先分配好内存,免得在使用中动态增长。
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方法预先分配好内存,免得在使用中动态增长。
相关文章
- 客服琐记 - 08 12, 2010
- 多线程并非万金油 - 07 13, 2010
- fedora 9 小集 - 01 05, 2009
感谢楼主的分析,最近做的项目也遇到了这个问题,跟楼主是一模一样的问题,在网上找了挺多原因的,看了楼主的分析才恍然大悟。最后采用了预先分配好vector大小,并保持不变的方法,解决了问题。 幸好该项目中vector的大小还是可以预先知道的,虽然多加了些代码,但是效率明显是提高了。