Is there atomic increment with the check preconditions, that the atomic value was less than the specified value?
Asked Answered
W

3

7

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.

Walkout answered 8/12, 2012 at 13:55 Comment(8)
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.).Andris
@KerrekSB - this code looks broken: if val is changed after it is read into old_val this will infinite loop.Doha
@djechlin: well, as with any CAS loop you can starve it, that's true. But I wouldn't hold that against the code.Andris
@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.Walkout
You should read from val in the loop, not before it.Doha
@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.Walkout
@Walkout - yes, you are right, I did not know that.Doha
@Alex, your solution is neat as it avoids integer overflow. A naive approach would be something like auto old= atomicint++; if (old<less_than) { . . ..Armenian
E
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.

Enki answered 12/9, 2013 at 2:42 Comment(0)
H
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.

Heighho answered 12/9, 2013 at 3:7 Comment(0)
E
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.

Enki answered 12/9, 2013 at 2:42 Comment(0)
A
-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

Autogiro answered 8/12, 2012 at 14:22 Comment(4)
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.Inartificial
Yeah sorry I'm downvoting this per above comment, using locks is essentially orthogonal to answering the question.Doha
But he wants an atomic increment and there is no way to implement something atomic other than using mutex or semaphoreAutogiro
@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.Walkout

© 2022 - 2024 — McMap. All rights reserved.