Linux 对共享内存的原子访问
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8759429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Atomic access to shared memory
提问by excalibur
I have a shared memory between multiple processes that interpets the memory in a certain way. Ex:
我在多个进程之间有一个共享内存,它以某种方式插入内存。前任:
DataBlock {
int counter;
double value1;
double ... }
What I want is for the counter to be updated/incremented atomically. And for a memory release to happen on that address. If I werent using shared memory, for example, it would be something like
我想要的是计数器以原子方式更新/递增。并且在该地址上发生内存释放。例如,如果我不使用共享内存,它将类似于
std::atomic<int> counter;
atomic_store(counter, newvalue, std::memory_order_release); // perform release operation on the affected memory location making the write visible to other threads
How do I achieve this for a random memory location (interpreted to be DataBlock counter >above). I can guarantee the address is aligned as required by the architecture (x86 linux)
- Make the update atomic - how? (i.e. atomicupdate(addr, newvalue))
- Memory syncing for multicore - (i.e. memorysync(addr)) - only way I can see is using the std::atomic_thread_fence(std::memory_order_release) - but this will "establish memory synchronization ordering of ALL atomic and relaxed atomic stores" - thats overkill for me - I just want the counter location to be synchronized. Appreciate any thoughts.
我如何为随机内存位置实现这一点(解释为数据块计数器 > 以上)。我可以保证地址按照架构要求对齐(x86 linux)
- 使更新原子化 - 如何?(即原子更新(地址,新值))
- 多核的内存同步 - (即 memorysync(addr)) - 我能看到的唯一方法是使用 std::atomic_thread_fence(std::memory_order_release) - 但这将“建立所有原子和宽松原子存储的内存同步排序” - 就是这样对我来说太过分了 - 我只想同步计数器位置。欣赏任何想法。
回答by edA-qa mort-ora-y
I can't answer with authority here, but I can give related information that might help.
我不能在这里权威地回答,但我可以提供可能有帮助的相关信息。
Mutexes can be created in shared memory and/or created to be cross-process. Pthread has a special creation flag, I can't remember if that uses shared memory, or you then share a handle. The linux "futex" can use shared memory directly (note the user address may differ, but the underlying real address should be the same)
Hardware atomics work on memory and not process variables. That is, your chip won't care which programs are modifying the variables, the lowest level atomics will thus naturally be cross-process. The same applies to fences.
C++11 fails to specify cross-process atomics. However, if they are lock-free (check the flag) it is hard to see how a compiler could implement them such that cross-process wouldn't work. But you'd be placing a lot of faith in your tool-chain and final platform.
CPU dependency guarantees also track real memory addresses, so as long as your program would be correct in a threaded form it should also be correct in its multi-process form (with respect to visibility).
Kerrek is correct, the abstract machine doesn't really mention multiple processes. However, its synchronization details are written in a way such that they'd equally apply to inter-process as they do to multi-thread. This relates to #3: it'd be hard for a compiler to screw this up.
互斥体可以在共享内存中创建和/或创建为跨进程。Pthread 有一个特殊的创建标志,我不记得它是否使用共享内存,或者您共享一个句柄。linux“futex”可以直接使用共享内存(注意用户地址可能不同,但底层真实地址应该是一样的)
硬件原子作用于内存而不是过程变量。也就是说,您的芯片不会关心哪些程序正在修改变量,因此最低级别的原子自然会是跨进程的。这同样适用于栅栏。
C++11 无法指定跨进程原子。但是,如果它们是无锁的(检查标志),则很难看出编译器如何实现它们以使跨进程不起作用。但是您会非常相信您的工具链和最终平台。
CPU 依赖性保证还跟踪实际内存地址,因此只要您的程序在线程形式中是正确的,它在多进程形式中也应该是正确的(关于可见性)。
Kerrek 是对的,抽象机器并没有真正提到多个进程。然而,它的同步细节的编写方式使得它们同样适用于进程间和多线程。这与#3 有关:编译器很难把它搞砸。
Short answer, there is no standards compliant way to do this. However, leaning on the way the standard defines mutli-threads there are a lot of assumptions you can make for a quality compiler.
简短的回答,没有符合标准的方法来做到这一点。然而,根据标准定义多线程的方式,您可以为高质量的编译器做出很多假设。
The biggest question is whether an atomic can simply be allocated in shared memory (placement new) and work. Obviously this would only work if it is a true hardware atomic. My guess however is that with a quality compiler/libary the C++ atomics should work find in shared memory.
最大的问题是原子是否可以简单地分配到共享内存(新的位置)并工作。显然,这只有在它是真正的硬件原子时才有效。然而,我的猜测是,使用高质量的编译器/库,C++ 原子应该可以在共享内存中找到。
Have fun verifying behaviour. :)
玩得开心验证行为。:)
回答by Jason
Since you're on Linux, you can use the gcc
atomic built-in __sync_fetch_and_add()
on the address for counter
... according to the gcc-documentation on atomic built-ins, this will also implement a full memory fence, not a release operation, but since you actually want a read-modify-write operation rather than simply a load (i.e., incrementing a counter is not just a load, but you have to read, then modify, and finally write-back the value), the full-memory fence is going to be a better choice to enforce the correct memory ordering for this operation.
由于您使用的是 Linux,您可以在地址上使用gcc
atomic built-in __sync_fetch_and_add()
for counter
... 根据atomic built-ins 上的gcc-documentation,这也将实现完整的内存栅栏,而不是释放操作,但是由于你实际上想要一个读-修改-写操作而不是简单的加载(即增加一个计数器不仅仅是一个加载,而是你必须读取,然后修改,最后写回值),全内存栅栏将是一个更好的选择来强制执行此操作的正确内存顺序。
回答by xgwang
i am looking at the standard draft N4820 [atomics.lockfree], and it says:
我正在查看标准草案 N4820 [atomics.lockfree],它说:
4 [Note: Operations that are lock-free should also be address-free. That is, atomic operations on the same memory location via two different addresses will communicate atomically. The implementation should not depend on any per-process state. This restriction enables communication by memory that is mapped into a process more than once and by memory that is shared between two processes. — end note]
4 [注意:无锁的操作也应该是无地址的。也就是说,通过两个不同地址对同一内存位置的原子操作将进行原子通信。实现不应依赖于任何每个进程的状态。此限制允许通过多次映射到进程的内存和在两个进程之间共享的内存进行通信。— 尾注]
so if you are targeting address-free, the prerequisite is lock-free and this can be checked by std::atomic.
因此,如果您的目标是无地址,则先决条件是无锁的,这可以通过 std::atomic 进行检查。
however, i am not sure how atomic
object shall be created. is it good enough to place the object in shared memory? i have not find out any specification on this usage while i do see such code usage on github.
但是,我不确定如何atomic
创建对象。将对象放在共享内存中是否足够好?我没有找到关于这种用法的任何规范,而我确实在 github 上看到了这样的代码用法。
(editor's note: you cast a pointer to shared memory, e.g.auto p = static_cast<atomic<int>*>(ptr);
Same as accessing shared memory as any other type.)
(编者注:您将指针投射到共享内存,例如auto p = static_cast<atomic<int>*>(ptr);
与访问任何其他类型的共享内存相同。)