Search code examples
c++c++11atomicstdatomic

How to implement an atomic increment of a pointer to an integer using std::atomic?


While porting some Windows C++ code to iOS, I need to provide an implementation of Win32's long InterlockedIncrement(long *p) call. This is easy enough using the functions defined in <libkern/OSAtomic.h>.

However, I am wondering whether it's possible to write it in a OS-agnostic way using just the C++11 facility, mainly <atomic>. I came up with this, which I am not sure accomplishes what I want:

inline long InterlockedIncrement(long* p)
{
    std::atomic<long&> atomicP(*p);
    return ++atomicP;
}

Does this work? Is that good enough? The two lines are not atomic, but the increment should be atomic, which is the key here.

All the examples of use for <atomic> that I found are different, where a std::atomic<T> is defined and used directly. Here I want to use an existing long variable that the callers passes to me by address. I couldn't find such an example.

Edit: Clang 3.2 (in Xcode 4.x) fails to compile ++atomicP with the error "cannot increment value of type std::atomic<long&>" (nor atomicP += 1 either).

What would be the correct way?

Edit again: a pointer implementation compiles...

inline long InterlockedIncrement(long* p)
{
    std::atomic<long*> atomicP(p);
    return ++(*atomicP);
}

But I'm afraid this doesn't work, since I don't increment an atomic type, but the value pointed by the pointer, which is not atomic.


Solution

  • Your example implementation is constructing a new atomic from a pointer each time. This is not the intended use of std::atomic and I do not believe it works how you would like.

    To my knowledge, the only way to do what you are looking to do (remove dependence on InterlockedIncrement in a platform independent way) is to replace all declarations for variables that you currently are calling Win32 "interlock" calls on with std::atomic versions of them. Then, you can remove the interlocked calls and use regular value semantics to modify the variable atomically. This is more readable (and more maintainable in the future), anyway.

    I understand you wish to leave existing (well tested) code in place but I don't think you can in your case.