在将一些Windows C ++代码移植到iOS时,我需要提供Win32 long InterlockedIncrement(long *p)
调用的实现。使用<libkern/OSAtomic.h>
中定义的函数很容易。
但是,我想知道是否有可能仅使用C ++ 11工具以OS {无关的方式编写它,主要是<atomic>
。我想出了这个,我不确定能实现我想要的东西:
inline long InterlockedIncrement(long* p)
{
std::atomic<long&> atomicP(*p);
return ++atomicP;
}
这有用吗?这够好吗?这两行不是原子的,但增量应该是原子的,这是关键。
我找到的<atomic>
的所有使用示例都不同,其中std::atomic<T>
被定义并直接使用。在这里,我想使用一个现有的长变量,调用者通过地址传递给我。我找不到这样的例子。
编辑:Clang 3.2(在Xcode 4.x中)无法编译++atomicP
,错误“无法增加std::atomic<long&>
类型的值”(也不是atomicP += 1
)。
什么是正确的方法?
再次编辑:指针实现编译......
inline long InterlockedIncrement(long* p)
{
std::atomic<long*> atomicP(p);
return ++(*atomicP);
}
但我担心这不起作用,因为我没有增加原子类型,而是指针指向的值,这不是原子的。
答案 0 :(得分:12)
您的示例实现每次都从指针构造一个新的原子。这不是std :: atomic的预期用途,我不相信它会如你所愿。
据我所知,执行您要做的事情的唯一方法(以独立于平台的方式移除对InterlockedIncrement的依赖)是替换当前使用std调用Win32“interlock”调用的变量的所有声明: :它们的原子版本。然后,您可以删除互锁调用并使用常规值语义以原子方式修改变量。无论如何,这更具可读性(并且在将来更易于维护)。
我知道您希望保留现有(经过良好测试的)代码,但我认为您不能这样做。
答案 1 :(得分:2)
我相信你可以使用atomic_fetch_add
操作。看一下示例here。
答案 2 :(得分:2)
__atomic_add_fetch
GCC扩展程序
在GCC 4.8中,C ++标准库使用GCC内置std::atomic::operator++
实现__atomic_add_fetch
,因此您可以编写:
inline long InterlockedIncrement(long* p)
{
return __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST);
}
我不确定clang,但似乎有一些选项,例如__c11_atomic_fetch_add
http://clang.llvm.org/docs/LanguageExtensions.html
正如其他人提到的,参数p
本身必须是std::atomic
才能使用标准库方法:将指针转换为原子并没有帮助,因为原子指针只作用于指针,而不是它指向的内容。