Baup
Baup

Reputation: 11

C++ atomic variable compare and increment

I would like to know how to make the following function in a whole atomic.

With my code, I believe there can be a situation that two threads both pass the condition, and return 0,1 respectively right?

static std::atomic<uintV> shared_v (0);
int compare_increment() {
  if (shared_v >= 10) {
    return -1;
  } 
  return shared_v++;

Any help would be appreciated.

Upvotes: 1

Views: 1731

Answers (2)

Zan Lynx
Zan Lynx

Reputation: 54353

I wrote one for a bit of fun.

$ cat compare-exchange-atomic-test.cpp 

#include <array>
#include <atomic>
#include <iostream>
#include <thread>

std::atomic<int> value{0};
std::atomic<int> loops{0};
int comparison_target = 10;

void f() {
  int v;
  do {
    v = value;
    if (v < comparison_target) {
      return;
    }
    ++loops;
  } while (!value.compare_exchange_weak(v, v + 1));
}

void g() {
  int i;
  for (i = 0; i < 1000; ++i) {
    f();
  }
}

int main(int argc, char *argv[]) {
  if (argc > 1) {
    comparison_target = std::stoi(argv[1]);
  }

  std::array<std::thread, 64> threads;
  for (auto &x : threads) {
    x = std::thread(g);
  }

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

  std::cout << value << ' ' << comparison_target << ' ' << loops << std::endl;
  return 0;
}

$ g++ -Wall -W -pedantic -g -O3 -flto -fno-fat-lto-objects -mcpu=native -DNDEBUG -pthread -MMD  -fPIC -fPIE -std=c++17  compare-exchange-atomic-test.cpp -pthread -flto -fno-fat-lto-objects  -o compare-exchange-atomic-test

$ ./compare-exchange-atomic-test 1
0 1 0

$ ./compare-exchange-atomic-test 0
64000 0 455100

$ ./compare-exchange-atomic-test 0
64000 0 550596

Upvotes: 1

Nate Eldredge
Nate Eldredge

Reputation: 58741

You can use compare_exchange_weak in a loop to achieve this sort of read-modify-write effect without a mutex.

Example (untested):

int compare_increment() {
    uintV old = shared_v.load();
    do {
        if (old >= 10)
            return -1;
    } while (!shared_v.compare_exchange_weak(old, old+1));
    return old;
}

Upvotes: 1

Related Questions