6

Is in the new standard C++ atomic increment operation with the check preconditions before the incremented the value, that the atomic value was less than the specified value?

Can I do it easier and faster than the following code?

int atomic_inc(std::atomic_int& val, int less_than) {
 int new_val;
 int old_val = val.load();
 do
 {
   if (old_val > less_than) return old_val;
   new_val = old_val + 1;
 } while (!val.compare_exchange_weak(old_val, new_val));

 return new_val;
}

If somebody don't know how works compare_exchange_weak: compare_exchange_weak reads val, compares with old_val, and if they are not equal then saves val to old_val. If it is equal then save new_val to val.

Alex
  • 12,578
  • 15
  • 99
  • 195
  • 2
    I don't think so. Your current code looks fine. If you started admitting some other checks, you'd have to justify why you wouldn't admit others (e.g. `increment_if_zero_mod_two` etc.). – Kerrek SB Dec 08 '12 at 14:24
  • 1
    @KerrekSB - this code looks broken: if `val` is changed after it is read into `old_val` this will infinite loop. – djechlin Dec 08 '12 at 14:48
  • @djechlin: well, as with any CAS loop you can starve it, that's true. But I wouldn't hold that against the code. – Kerrek SB Dec 08 '12 at 14:51
  • @djechlin: One can get rid of the loop? To make it wait-free instead lock-free. lock-free is always have a chance of being in an infinite loop, but progress is at least one thread is always assured. – Alex Dec 08 '12 at 18:46
  • 1
    You should read from val in the loop, not before it. – djechlin Dec 08 '12 at 19:10
  • @djechlin: No, compare_exchange_weak reads val, compares with old_val, and if they are not equal then saves val to old_val. If it is equal then save new_val to val. – Alex Dec 08 '12 at 21:28
  • @Alex - yes, you are right, I did not know that. – djechlin Dec 08 '12 at 22:09
  • @Alex, your solution is neat as it avoids integer overflow. A naive approach would be something like `auto old= atomicint++; if (old – Johan Lundberg Apr 24 '16 at 08:10

3 Answers3

2

Something I have done in the past, might work for you depending on what you're using this for.

If you can assume that val won't clip very often -- so that the possible optimization of not doing a CAS isn't going to save you much --, you can just blindly increment the value and adjust it after you read:

int atomic_inc(std::atomic_int& val, int less_than) {
    return std::min(++val, less_than);
}

And then occasionally clip val back down to less_than if needed, often enough that you don't have to worry about the int overflowing, and you're golden.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
1

No, there is no special support for incrementing values less than a value. Your code is as efficient as you can get. There is no wait-free variant in C++11

There is an unlimited number of possible "increment if X" patterns. The hardware manufacturers decided that "increment if not changed" is the only thing they need to support.

In theory you could invent a hardware platform with a special assembly code for it, but C++11 does not directly target that.

Cort Ammon
  • 10,221
  • 31
  • 45
-4

If you're using threads, you can use mutex to do an atomic increment. Here's how you'd do it in this case:

Declare and initialize mutex globally:

pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL)

In one thread:

int atomic_inc(std::atomic_int& val, int less_than) {
    pthread_mutex_lock(&lock);
    int newVal = val.load();
    if (newVal < less_than)
        newVal++
    pthread_mutex_unlock(&lock);
    return new_val;
}

You would have to lock and unlock the mutex before modifying val in any other thread.

For more information on mutex: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SYNCHRONIZATION

Uzair Farooq
  • 2,402
  • 3
  • 24
  • 37
  • 1
    But now you're introducing contention, aren't you. The whole point of atomic types is so that you don't need to just throw a mutex at everything any more. – Lightness Races in Orbit Dec 08 '12 at 14:29
  • 1
    Yeah sorry I'm downvoting this per above comment, using locks is essentially orthogonal to answering the question. – djechlin Dec 08 '12 at 14:45
  • But he wants an atomic increment and there is no way to implement something atomic other than using mutex or semaphore – Uzair Farooq Dec 08 '12 at 14:49
  • @Uzair Farooq: Atomic increment can be without mutex. Wait-free always better than mutex. But for a lot of cores lock-free can be badly than mutex. – Alex Dec 08 '12 at 18:49