我阅读了C ++ Standard(n4713)的§32.6.1 3:
无锁的操作也应无地址。那是, 通过两个不同的原子对同一内存位置进行原子操作 地址将自动进行通信。实施不应该 取决于任何按进程的状态。此限制使 内存通信多次映射到一个进程 以及两个进程之间共享的内存。
因此,听起来可以在同一存储位置上执行无锁原子操作。我不知道该怎么办。
假设我在Linux上有一个命名的共享内存段(通过shm_open()和mmap())。例如,如何在共享内存段的前4个字节上执行无锁操作?
起初,我以为我可以reinterpret_cast
指向std::atomic<int32_t>*
的指针。但是后来我读了this。首先指出std :: atomic的T或对齐方式可能不相同:
当我们设计C ++ 11原子时,我被误认为 可以半便携式地将原子操作应用于数据 使用诸如
之类的代码未声明为原子的
int x; reinterpret_cast<atomic<int>&>(x).fetch_add(1);
如果atomic和int的表示形式显然会失败 不同,或者它们的对齐方式不同。但是我知道这不是 我关心的平台上的问题。而且,在实践中,我可以轻松地进行测试 通过在编译时检查大小和对齐方式来解决问题 匹配。
在这种情况下,这对我很好,因为我在同一台计算机上使用共享内存,并且在两个不同进程中强制转换指针将“获取”相同的位置。但是,该文章指出,编译器可能不会将强制转换的指针视为指向原子类型的指针:
但是,即使在以下平台上,也不能保证这是可靠的 可能会期望它起作用,因为它可能会使基于类型的混淆 编译器中的别名分析。编译器可能会假设int为 也不能作为
atomic<int>
访问。 (请参见最后一个3.10 [Basic.lval] 段落。
欢迎任何输入!
答案 0 :(得分:4)
C ++标准本身并不涉及多个进程,因此不会有任何正式的答案。这个答案将假定程序在同步方面的行为与线程在某种程度上相同。
第一个解决方案需要C ++ 20 atomic_ref
void* shared_mem = /* something */
auto p1 = new (shared_mem) int; // For creating the shared object
auto p2 = (int*)shared_mem; // For getting the shared object
std::atomic_ref<int> i{p2}; // Use i as if atomic<int>
这可以防止共享内存中存在不透明的原子类型,从而使您可以精确控制其中的确切内容。
C ++ 20之前的解决方案是
auto p1 = new (shared_mem) atomic<int>; // For creating the shared object
auto p2 = (atomic<int>*)shared_mem; // For getting the shared object
auto& i = *p2;
或使用C11 atomic_load
和atomic_store
volatile int* i = (volatile int*)shared_mem;
atomic_store(i, 42);
int i2 = atomic_load(i);
答案 1 :(得分:1)
是的,对于所有这些,C ++标准有点meal嘴。
如果您使用的是Windows(可能不是),则可以使用InterlockedExchange()
等,它提供了所有必需的语义,并且不在乎所引用的对象在哪里(这是一个LONG *)。
在其他平台上,gcc有一些atomic builtins可能对此有所帮助。他们可能使您摆脱标准编写者的暴政。麻烦的是,很难测试生成的代码是否是防弹的。
答案 2 :(得分:1)
在所有主流平台上, 您可以使用以下方法检查这些假设: 在并非如此的奇异C ++实现中,想要在共享内存上使用您的代码的人将需要做其他事情。 或者如果 all 从所有进程始终使用std::atomic<T>
确实具有与T
相同的大小,但是如果T
具有alignof static_assert(sizeof(T) == sizeof(std::atomic<T>),
"atomic<T> isn't the same size as T");
static_assert(std::atomic<T>::is_always_lock_free, // C++17
"atomic<T> isn't lock-free, unusable on shared mem");
auto atomic_ptr = static_cast<atomic<int>*>(some_ptr);
// beware strict-aliasing violations
// don't also access the same memory via int*
// unless you're aware of possible issues
// also make sure that the ptr is aligned to alignof(atomic<T>)
// otherwise you might get tearing (non-atomicity)
atomic<T>
访问共享内存,那没有问题,您只需要无锁来保证无地址。 (您确实需要检查以下内容:std :: atomic将锁的哈希表用于非无锁。这取决于地址,并且单独的进程将具有单独的锁的哈希表。)