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.
__atomic_add_fetch
GCC extension
In GCC 4.8, the C++ standard library implements std::atomic::operator++
with the GCC built-in __atomic_add_fetch
, so you could write:
inline long InterlockedIncrement(long* p)
{
return __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST);
}
I'm not sure for clang, but there seem to be some options like __c11_atomic_fetch_add
http://clang.llvm.org/docs/LanguageExtensions.html
As others mentioned, the argument p
itself would have to be std::atomic
for you to use only the standard library methods: converting the pointer into atomic does not help because the atomic pointer only acts on the pointer, not on what it points to.
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.
I believe you could use an atomic_fetch_add
operation. Take a look at the example here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With