gpt4 book ai didi

c++ - 线程lambda中的原子更新

转载 作者:行者123 更新时间:2023-12-02 10:04:46 25 4
gpt4 key购买 nike

我认为以这种方式在线程内更新原子值是不好的(总和有时看起来不太好)

    std::atomic<double> e(0);

auto worker = [&] (size_t begin, size_t end, std::atomic<double> & acc) {
double ee = 0;
for(auto k = begin; k != end; ++k) {
ee += something[k];
}
acc.store( acc.load() + ee );
};

std::vector<std::thread> threads(nbThreads);
const size_t grainsize = miniBatchSize / nbThreads;

size_t work_iter = 0;
for(auto it = std::begin(threads); it != std::end(threads) - 1; ++it) {
*it = std::thread(worker, work_iter, work_iter + grainsize, std::ref(e));
work_iter += grainsize;
}
threads.back() = std::thread(worker, work_iter, miniBatchSize, std::ref(e));

for(auto&& i : threads) {
i.join();
}

虽然使用锁卫似乎还可以
    std::atomic<double> e(0);
std::mutex m;

auto worker = [&] (size_t begin, size_t end, std::atomic<double> & acc) {
double ee = 0;
for(auto k = begin; k != end; ++k) {
ee += something[k];
}
{
const std::lock_guard<std::mutex> lock(m);
acc.store( acc.load() + ee );
}
};

std::vector<std::thread> threads(nbThreads);
const size_t grainsize = miniBatchSize / nbThreads;

size_t work_iter = 0;
for(auto it = std::begin(threads); it != std::end(threads) - 1; ++it) {
*it = std::thread(worker, work_iter, work_iter + grainsize, std::ref(e));
work_iter += grainsize;
}
threads.back() = std::thread(worker, work_iter, miniBatchSize, std::ref(e));

for(auto&& i : threads) {
i.join();
}

我是对的,我在这里想念什么?是std::ref(e)的问题吗?

最佳答案

您希望加载和存储都作为原子 Action 发生。目前,您的代码可以:

acc.store(acc.load() + ee);

现在想象一下,在执行 load()之后立即中断了一个线程(让我们调用已加载的值 acc_old)。另一个线程做它的事情(并因此修改 acc),然后第一个线程再次运行。它不会重新加载 acc,因为它已经加载了它的值。因此,此线程现在将更新 acc以包含 acc_old + ee。糟糕,结果不对。

而是使用 fetch_add operator+= 。两者都保证了整个加法操作的原子行为。即:
acc += ee; // or
acc.fetch_add(ee);

编辑:请注意,仅从C++ 20开始的浮点原子才支持这些功能。对于整数类型,从C++ 11开始支持它们。因此,如果需要浮点,则可能必须坚持使用互斥量。在那种情况下,我建议将 double 值和互斥体包装在一个类中,这样就不会意外地以错误的方式使用它。

关于c++ - 线程lambda中的原子更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60796997/

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