如何使用std::atomic实现指向整数的指针的原子增量?

问题描述 投票:0回答:3

将一些 Windows C++ 代码移植到 iOS 时,我需要提供 Win32 的

long InterlockedIncrement(long *p)
调用的实现。使用
<libkern/OSAtomic.h>
中定义的函数很容易做到这一点。

但是,我想知道是否可以仅使用 C++11 工具以与操作系统无关的方式编写它,主要是

<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);
}

但是恐怕这不起作用,因为我不增加原子类型,而是增加指针指向的值,这不是原子的。

c++ c++11 atomic stdatomic
3个回答
13
投票

您的示例实现是每次从指针构造一个新的原子。这不是 std::atomic 的预期用途,我不相信它会按照您想要的方式工作。

据我所知,完成您想要做的事情的唯一方法(以独立于平台的方式消除对 InterlockedIncrement 的依赖)是用 std::atomic 替换您当前调用 Win32“互锁”调用的变量的所有声明它们的版本。然后,您可以删除互锁调用并使用常规值语义以原子方式修改变量。无论如何,这更具可读性(并且将来更易于维护)。

我知道您希望保留现有的(经过充分测试的)代码,但我认为您不能在您的情况下这样做。


4
投票

__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
才能仅使用标准库方法:将指针转换为原子并没有帮助,因为原子指针仅作用于指针,而不作用于它的对象指向。


2
投票

我相信你可以使用

atomic_fetch_add
操作。看一下示例这里

© www.soinside.com 2019 - 2024. All rights reserved.