多个线程同时在同一向量的不同向量上添加元素发生错误

Posted

技术标签:

【中文标题】多个线程同时在同一向量的不同向量上添加元素发生错误【英文标题】:Multiple threads add elements concurrently on different vectors of the same vector occurs error 【发布时间】:2020-03-12 09:25:40 【问题描述】:
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>

struct A 
    std::vector<int> a;
;

struct B
    std::vector<A> b;
    std::mutex mtx;
;

void work(int id, struct B& b) 
    std::unique_lock<std::mutex> lck(b.mtx);

    b.b.push_back(A());
    struct A& a = b.b.back();

    lck.unlock();

    for(int i = 0; i < 1000; i++) 
        std::cout << id << " " << i << std::endl;
        a.a.push_back(i);
    


int main() 
    struct B b;
    std::thread t1, t2;

    t1 = std::thread([&] 
        work(1, b);
    );

    t2 = std::thread([&] 
        work(2, b);
    );

    t1.join();
    t2.join();

    return 0;

此代码出现一些错误(如分段错误)

正如我在上面写的,struct B 的向量为 struct Astruct A 的向量为 int

第 1 步)每个线程将新的 struct A 元素推送到具有临界区的同一向量 (b.b)。

第 2 步)之后,每个线程将新的 int 元素推送到 struct A 的向量 a 中,每个都在没有临界区的情况下创建。

我认为将新元素同时推送到同一个向量应该会出现一些问题,但是将新元素同时推送到不同的向量应该不会出现错误。

如果我将整个work 函数放入临界区,则不会发生错误。

因此,我得出结论,将新元素推送到不同的向量不会发生错误,但是如果它们在同一个向量中,则会发生错误。

但我无法解释原因。有人请告诉我这件事。 :(

【问题讨论】:

我想我找到了原因。当我将新的struct A 推送到向量b.b 时,向量b.b 将被重新分配以增加容量。结果,struct A&amp; a 将被释放并发生错误。 【参考方案1】:

当第二个线程将新值推送到b.b 时,该向量可能会调整大小。如果它被调整大小,所有对其元素的引用都将失效。所以第一个线程的引用A&amp; a就失效了。

你可以

使用std::list(链表) resize() 向量 b.b 在使用它之前,所以它不需要稍后调整大小(或reserve(),在这里没有太大区别)

【讨论】:

【参考方案2】:

std::vector 在您push_back 时重新分配其内存,因为它需要额外的内存。 如果您 reserve() 向量,它不会重新分配,直到它需要额外的内存。

【讨论】:

以上是关于多个线程同时在同一向量的不同向量上添加元素发生错误的主要内容,如果未能解决你的问题,请参考以下文章

C++:在多个线程中访问同一数组/向量的不同单元是不是会产生数据竞争?

多个线程可以在不同的地方访问一个向量吗?

有没有办法将两个或多个不同的类链接到一个类中(然后在向量上使用)?

如果线程必须写在同一个向量上,是不是可以使用线程

java多线程

线程知识点