gpt4 book ai didi

c++ - 使用 std::atomic 索引在大型数组上异步并行化操作有多安全

转载 作者:搜寻专家 更新时间:2023-10-31 01:27:22 29 4
gpt4 key购买 nike

我有一个并行例程来对大型指针数组中的每个对象执行一系列计算,其中计算要求每个线程能够读取所有其他对象,但只会写入一个对象。我设置它类似于下面

#include <atomic>
#include <thread>

void threadFunction(Object** objects, int n);

std::atomic<int> idx;
int nobjects = 10000;

int main() {
int nthreads = 4;
Object** objects = new Object*[nobjects];

idx = 0;
std::thread threads[nthreads];
for (int ii = 0; ii < nthreads; ii ++) {
threads[ii] = std::thread(threadFunction, objects, ii);
}

while (idx < nobjects - 1) {} // Wait until all the calculations have been done

for (int ii = 0; ii < nthreads; ii ++) {
threads[ii].join();
}
}

void threadFunction(Object** objects, int n) {
Object* current = NULL;
while (idx < nobjects - 1) {
current = objects[idx++];
// do calculation
}
}

其中 Object 是一个自定义类,但出于这些目的可以用原语代替。我的问题是这样做有多“安全”?我知道 atomic 类型受到保护,不会被部分写入,但我怎么能确定它每次都能工作,即使对于大型数组也是如此?

这可能太具体了,但如果能得到任何帮助,我将不胜感激。谢谢

最佳答案

正如其他人在评论中指出的那样,您在检查循环条件和使用 idx 的值之间存在竞争条件。这可能会导致您读到数组末尾。您的线程函数只需要稍微调整一下:

void threadFunction(Object** objects, int n) {
Object* current = NULL;
while (true) {
int next = idx++;
if (next < nobjects - 1) {
current = objects[next];
// do calculation
} else {
break;
}
}
}

一般来说,证明无锁算法是正确的是很难的,只能通过仔细检查代码来完成。在任何情况下,数组的大小都不会影响该算法的正确性。

使用标准库

虽然这没有被特别要求,但可能值得指出的是,这一切都可以通过标准库完成(它避免了棘手的安全问题并处理了分区等问题)。类似于以下内容:

void DoCalculations(Object& obj)
{
// details...
}

// later...

std::vector<std::unique_ptr<Object>> objects = CreateObjects();
std::for_each(
std::execution::par,
objects.begin(),
objects.end(),
[] (std::unique_ptr<Object> const& p) { DoCalculations(*p); });

关于c++ - 使用 std::atomic<int> 索引在大型数组上异步并行化操作有多安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53507465/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com