0

我想使用自定义策略将元素从一个数组复制到另一个数组中,例如如果元素不为零,则将其复制到另一个数组中。代码可能如下所示:

double src[NUM] = {a0, a1, a2, ..., an};
double dst[NUM] = {0}; // initialize dst all elements as 0
double twodouble[NUM] = {0};
tbb::atomic<int> count = 0;

// this parallel just want to copy non-zero elements from src int dst
tbb::paralell_for(tbb::blocked_range<szie_t>(0, NUM),
  [&](const tbb::blocked_range<szie_t>& r){
    for (szie_t i = r.begin(); i < r.end(); ++i) {
        if (std::abs(src[i]) < esp) continue;
        dst[count] = src[i];
        twodouble[count] = 2.0 * src[i];
        count++;
}
    
});

事实上,dst 的元素可能是这样的:[a0, a1, 0, am, ..., 0, a_(count-1)],显然,src 中的一些非零元素并没有被复制到 dst 中。

我的电脑有 12 个 CPU,我认为 parallel_for 子块范围到不同的 CPU 来复制元素,所以这个副本可能是线程安全的,但实际上不是。该代码有什么问题以及如何纠正它?

4

1 回答 1

1

问题是使用共享count原子来定义放置顺序。它会导致竞争条件,因为多个线程可以同时写入同一内​​存。此外,它会导致顺序中断,因为不能保证对第一个src元素执行第一次写入操作。

为了避免竞争条件并正确复制数据,您不仅应该使用本地blocked_range索引来访问,src而且还应该使用dest.

代码应该类似于以下内容:

tbb::parallel_for( tbb::blocked_range<size_t>(0, NUM),
  [&](const tbb::blocked_range<size_t>& r) {
    for (size_t i = r.begin(); i < r.end(); ++i) {
      if (std::abs(src[i]) < esp) continue;
      dst[i] = src[i];
      twodouble[i] = 2.0 * src[i];
    }
  }
);
于 2021-10-01T14:29:15.593 回答