如何正确地增加c++ 11的std::atomic

How can I properly increase C++11 std::atomic?

本文关键字:std atomic c++ 正确地 增加      更新时间:2023-10-16

我是多线程编程的新手,我在c++ 11中找到了std::atomic

所以,我试着算出原子操作需要多少时间。

我试过这个代码:

using namespace std;
using namespace std::chrono;
constexpr int NUM_THREADS = 8;
constexpr int LIMIT = 100000;
atomic<int> sum = 0;
void foo(int idx) {
    while (true) {
        if (sum.load() >= LIMIT) {
            return;
        }
        sum.fetch_add(1);
    }
}

with main:

int main(void) {
    thread threads[NUM_THREADS];
    auto start = high_resolution_clock::now();
    for (int i = 0; i < NUM_THREADS; i++) {
        threads[i] = thread(&foo, i);
    }
    for (int i = 0; i < NUM_THREADS; i++) {
        threads[i].join();
    }
    auto du = high_resolution_clock::now() - start;
    cout << "computing timett" << duration_cast<milliseconds>(du).count() << "ms" << endl;
    cout << "number of threadt" << NUM_THREADS << endl;
    cout << "sumttt" << sum << endl;
    return 0;
}

sum并不总是与LIMIT相同。

据我所知,原子操作在被调用时是线程安全的。所以,是的,我认为我的代码是错误的,但是我不知道如何使它正常工作。

我怎么能得到一个正确的结果与main ?

(好吧,这个版本将使sumLIMIT相等,但我认为这不是一个好方法…)

void foo(int idx) {
    for (int i = 0; i < LIMIT / NUM_THREADS; i++) {
        sum.fetch_add(1);
    }
}

正如在评论中所说,您的问题是变量在加载它和增加它的时间之间由另一个线程更改。

你可以改变你的循环,例如像这样来修复它:

while (true) {
    auto current = sum.load();        
    if (current >= LIMIT) {
        return;
    }
    auto next = current + 1;
    sum.compare_exchange_strong(current, next));
}

operator++是原子上的原子类型,所以您需要做的就是:

void foo(int idx) {
    while (true) {
        if (sum++ >= LIMIT) {
            return;
        }
    }
}

一旦其中一个线程将sum增加到LIMIT,其他线程也将看到该值大于或等于LIMIT并返回。这里有一个风险:如果线程数大于std::numeric_limits<int>::max() - LIMIT,那么后面的一个线程将使sum超过int的最大值。只要LIMIT是明智的这不是问题。