首页 文章

编写std :: vector vs plain数组的线程安全性

提问于
浏览
18

我读过on Stackoverflownone of the STL containers are thread-safe for writing . 但这在实践中意味着什么?这是否意味着我应该将可写数据存储在普通数组中?

我期望对 std::vector::push_back(element) 的并发调用可能导致数据结构不一致,因为它可能需要调整向量的大小 . 但是这样的情况呢,不涉及调整大小:

1)使用数组:

int data[n];
// initialize values here...

#pragma omp parallel for
for (int i = 0; i < n; ++i) {
    data[i] += func(i);
}

2)使用`std :: vector``:

std::vector<int> data;
data.resize(n);
// initialize values here...

#pragma omp parallel for
for (int i = 0; i < n; ++i) {
    data[i] += func(i);
}

第一个实现是否真的比第二个更好a)在线程安全方面和b)在性能方面?我更喜欢使用std :: vector,因为我对C风格的数组不太熟悉 .

编辑:我删除了 #pragma omp atomic update 保护写 .

4 回答

  • 23

    这两个人同样安全 . 如果没有从多个线程访问任何元素就可以了 . 您的并行循环将只访问每个元素一次,因此只能访问一个线程 .

    标准中有空间,容器的成员函数是非线程安全的 . 在这种情况下,您使用 vector<int>::operator[] ,因此您'd want an explicit guarantee of thread-safety for that member, which seems reasonable since calling it even on a non-const vector doesn' t修改向量本身 . 所以我怀疑's a problem in this case, but I haven' t寻找保证[编辑:rici找到它] . 即使它可能不安全,你可以在循环之前做 int *dataptr = &data.front() 然后索引 dataptr 而不是 data .

    顺便说一句,这个代码不能保证 vector<bool> 的安全,因为它是一个特殊情况,多个元素在一个对象中共存 . 对于 bool 数组来说是安全的,因为它的不同元素是不同的"memory locations"(C11中为1.7) .

  • 18

    对于指定数据争用规则的c 11,描述了容器的线程安全性 . 该标准的相关部分是§23.2.2,第2段:

    尽管如此(17.6.5.9),除了vector <bool>之外,同时修改同一序列中不同元素中包含对象的内容时,需要实现以避免数据争用 . [注意:对于大小大于1的向量<int> x,x [1] = 5和* x.begin()= 10可以在没有数据争用的情况下同时执行,但是x [0] = 5和*并发执行的x.begin()= 10可能导致数据竞争 . 作为一般规则的例外,对于向量<bool> y,y [0] = true可以与y [1] = true竞争 . - 尾注]

    除非特别允许,否则上面提到的§17.6.5.9基本上禁止任何标准库接口的任何并发修改,因此我引用的部分确切地告诉您允许的内容(包括您的使用) .

    由于Steve Jessop提出了这个问题,§23.2.2的第1段明确允许在序列容器中同时使用 []

    为避免数据争用(17.6.5.9),实现应将以下函数视为const:begin,end,rbegin,rend,front,back,data,find,lower_bound,upper_bound,equal_range,at和,除了关联或无序关联容器,operator [] .

  • 2

    它的主要意思是,如果你有多个线程访问向量,你不能依赖C来防止多个并发写入破坏数据结构 . 所以你需要使用某种防守 . 另一方面,如果你的程序没有使用多个线程,就像你的例子似乎没有,你就完全没问题了 .

  • 1

    在这种情况下,您应该只使用必要数量的值构建向量?一切都会好起来的 .

    std::vector<int> data(n, 0);
    

    resize() 效果很好 . 表现将是平等的 . 多线程访问不会破坏向量的原因是:您的数据位于其位置,不会从那里移动 . OMP线程一次不会访问同一个元素 .

相关问题