HCS*_*CSF 3 c++ shared-memory c++11 stdatomic
我阅读了 C++ 标准 (n4713) 的 § 32.6.1 3:
无锁的操作也应该是无地址的。也就是说,通过两个不同地址对同一内存位置的原子操作将进行原子通信。实现不应依赖于任何每个进程的状态。此限制允许通过多次映射到进程的内存和在两个进程之间共享的内存进行通信。
所以听起来可以在同一内存位置执行无锁原子操作。我想知道怎么做。
假设我在 Linux 上有一个命名的共享内存段(通过 shm_open() 和 mmap())。例如,如何对共享内存段的前 4 个字节执行无锁操作?
起初,我以为我可以只reinterpret_cast指向std::atomic<int32_t>*. 但后来我读到了这个。它首先指出 std::atomic 可能没有相同大小的 T 或对齐:
当我们设计 C++11 原子时,我误以为可以使用诸如
int x; reinterpret_cast<atomic<int>&>(x).fetch_add(1);
Run Code Online (Sandbox Code Playgroud)
如果 atomic 和 int 的表示不同,或者它们的对齐方式不同,这显然会失败。但我知道这在我关心的平台上不是问题。而且,在实践中,我可以通过在编译时检查大小和对齐方式匹配来轻松测试问题。
Tho,在这种情况下对我来说很好,因为我在同一台机器上使用共享内存,并且在两个不同的进程中投射指针将“获取”相同的位置。但是,文章指出编译器可能不会将强制转换的指针视为指向原子类型的指针:
然而,这不能保证是可靠的,即使在人们可能期望它工作的平台上,因为它可能会混淆编译器中基于类型的别名分析。编译器可能会假设 int 也不会作为
atomic<int>. (见 3.10,[Basic.lval],最后一段。)
欢迎任何输入!
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>
Run Code Online (Sandbox Code Playgroud)
这可以防止共享内存中存在不透明的原子类型,这使您可以精确控制其中的确切内容。
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;
Run Code Online (Sandbox Code Playgroud)
或者使用 C11atomic_load和atomic_store
volatile int* i = (volatile int*)shared_mem;
atomic_store(i, 42);
int i2 = atomic_load(i);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
871 次 |
| 最近记录: |