多线程使用vector
文章目录
- 多线程使用vector
- 场景描述
- 原因分析
- 解决
- 代码测试
- 不扩容和提前扩容 size 与 capacity 变化
- 欢迎关注公众号【三戒纪元】
场景描述
最近在看代码优化,看到有这样的代码:
std::vector<int> valid_indices;
void SimbaSegmenter::GridFilter::Clean() {
valid_indices.reserve(rows * cols);
valid_indices.clear();
}
第一反应是,既然是Clean函数,肯定就是想清空这个数组,清空之前还要reserve一下,不是多此一举吗?
于是将第4行代码去掉了。
程序会报错:
0x7f8fd86169a7 std::vector<>::emplace_back<>()
原因分析
原本代码思路:在对valid_indices 赋值之前,先清空一下,然后将符合条件的数存入 valid_indices 数组。
问题在于程序使用的是多线程。
代码单线程测试了一下,也是没问题的,多线程的问题出在哪里呢?
问题就是出在赋值 emplace_back 时,如果发现 容量capacity 不够时,vector 会扩容。
多个线程同时到达 vector 的 emplace_back 语句,如果发现 capacity 不够了,开始扩容。这时几个线程同时扩容,就会造成资源竞争冲突,就会报错。
而如果加上第4句,先扩容到1个很大的范围,但是clear仅仅是将成员清除,使得size为0,因此多线程 emplace_back的时候,就能够直接emplace_back了,不会发生扩容问题。
解决
多线程需要同时对同一个vector进行写入的时候,先扩容到一个值,避免各个线程单独扩容,保证程序稳定有效进行。
代码测试
不扩容和提前扩容 size 与 capacity 变化
int main() {
std::vector<int> randy3;// 初始化: size : 0, capacity: 0
randy3.reserve(2); // reserve size : 0, capacity: 2
std::cout << "reserve size: " << randy3.size() << ", capacity: " << randy3.capacity() << std::endl;
std::vector<int> randy2; // 初始化: size : 0, capacity: 0
std::cout << "1 size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.clear(); // 清空size, size : 0, capacity: 0
std::cout << "2 clear size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.resize(2); // 扩容 capacity 为2 , size : 0, capacity: 0
std::cout << "3 size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.clear(); // 清空size, size : 0, capacity: 2
std::cout << "4 clear size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.emplace_back(2); // emplace_back 1 个元素, size : 1, capacity: 2
std::cout << "5 clear size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.emplace_back(13);// 再 emplace_back 1 个元素, size : 2, capacity: 2
std::cout << "6 clear size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
randy2.emplace_back(22); // emplace_back 第 3 个元素, size : 3, capacity: 4
std::cout << "7 clear size: " << randy2.size() << ", capacity: " << randy2.capacity() << std::endl;
}
结果:
reserve size: 0, capacity: 2
1 size: 0, capacity: 0
2 clear size: 0, capacity: 0
3 size: 2, capacity: 2
4 clear size: 0, capacity: 2
5 clear size: 1, capacity: 2
6 clear size: 2, capacity: 2
7 clear size: 3, capacity: 4