繁体   English   中英

从shm_open()+ mmap()更改共享内存的可见性

[英]Visibility of change to shared memory from shm_open() + mmap()

假设我在CentOS 7 x86_64 + GCC 7上。

我想在共享内存中创建一个ringbuffer。

如果我有两个进程Producer和Consumer,并且两者共享一个命名的共享内存,它通过shm_open()+ mmap()创建/访问。

如果制作人写了类似的东西:

struct Data {
uint64_t length;
char data[100];
}

随机时间到共享内存,消费者不断轮询共享内存进行读取。 我是否会遇到某种同步问题,即成员长度可见,但成员数据仍处于编写过程中? 如果是,那么避免这个问题的最有效技术是什么?

我看到这篇文章: 共享内存IPC同步(无锁)

但我希望能够更深入,更低级地了解在两个流程之间有效同步所需的内容。

提前致谢!

为避免这种情况,您可能希望使结构std::atomic并使用acquire-release内存排序访问它。 在大多数现代处理器上,插入的指令是内存屏障,它保证编写器在开始写入之前等待所有负载完成,并且读取器在开始读取之前等待所有存储完成。

此外,还有POSIX中的锁定原语,但<atomic>标题更新,你可能想要的。

标准说的是什么

来自[atomics.lockfree],重点补充说:

无锁的操作也应该是无地址的。 也就是说,通过两个不同地址在同一存储器位置上的原子操作将以原子方式进行通信。 实现不应该依赖于任何每个进程的状态。 此限制允许通过多次映射到进程的内存以及在两个进程之间共享的内存进行通信。

对于可锁定的原子,标准在[thread.rec.lockable.general]中说,重点是:

执行代理是诸如可以与其他执行代理并行执行工作的线程之类的实体。 [...]实施或用户可能会引入其他类型的代理, 例如流程 [....]

您有时会看到声称该标准没有提及使用<atomic>原语与进程之间共享的内存,只有线程。 这是不正确的。

但是,通过共享内存将指针传递给另一个进程将无法工作,因为共享内存可能会映射到地址空间的不同部分,当然,指向不在共享内存中的任何对象的指针也是正确的。 共享内存中对象的索引和偏移量。 (或者,如果你真的需要指针,Boost提供IPC安全包装器。)

是的,您最终会遇到数据争用,不仅是在写入data之前写入和读取的length ,而且这些成员的一部分将与您的进程读取不同步。

虽然无锁是一种新趋势,但我建议你选择一个更简单的工具作为你的第一个IPC同步工作:信号量。 在linux上,以下手册页将非常有用:

这个想法是让两个进程发信号通知它正在读取或编写共享内存段的另一个进程。 使用信号量,您可以编写进程间互斥:

Producer:
while true:
    (opt) create resource
    lock semaphore (sem_wait)
    copy resource to shm
    unlock semaphore (sem_post)

Consumer:
while true:
    lock semaphore (sem_wait)
    copy resource to local memory
        or crunch resource
    unlock semaphore (sem_post)

如果例如Producer写入shm而Consumer调用sem_wait ,则Consumer将阻塞,直到Producer将调用sem_post但是 ,你无法保证 Producer不会再去另一个循环,连续两次写入消费者将被唤醒。 你必须建立一个不确定生产者和消费者的机制。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM