在不同步的情况下读写 SysV 共享内存(使用信号量、C/C++、Linux)

Posted

技术标签:

【中文标题】在不同步的情况下读写 SysV 共享内存(使用信号量、C/C++、Linux)【英文标题】:Reading and writing to SysV shared memory without synchronization (use of semaphores, C/C++, Linux) 【发布时间】:2010-06-10 18:23:02 【问题描述】:

我使用 SysV 共享内存让两个进程相互通信。我不希望代码变得复杂,所以我想知道我是否真的必须使用信号量来同步对共享内存的访问。在我的 C/C++ 程序中,父进程从共享内存读取,子进程写入共享内存。我写了两个测试应用程序,看看我是否可以产生某种错误,比如分段错误,但我不能(Ubuntu 10.04 64bit)。即使两个进程在一个while循环中不停地写入同一个共享内存也不会产生任何错误。

希望有人有这方面的经验,可以告诉我是否真的必须使用信号量来同步访问,或者我是否可以不同步。

谢谢

【问题讨论】:

【参考方案1】:

如果您不使用某种互斥锁,那么您将自己暴露在与中断相关的奇怪而奇妙的计时错误中,而不是其他任何事情。

假设您的孩子在共享内存被抢占时正在写入中途。共享内存现在处于“坏”状态——它的一部分与子进程的一种状态有关,其余的与之前的状态有关——你的父进程可能会在子进程之前被重新激活。然后,您的状态已损坏。

可能能够在短期内摆脱这个问题,但您稍后发现奇怪的错误。

【讨论】:

谢谢,感谢您的回答。【参考方案2】:

写入正确映射的内存地址不会产生分段错误,无论有多少进程尝试“同时”执行此操作。同步的目的是为了保持数据的一致性。

如果满足以下条件,您可以避免信号量和互斥锁:

    您只有一个线程写入给定地址。

    写入的数据是原子的——意味着它可以在一次 I/O 操作中传输。字符和整数等简单的东西在传输时通常是原子的。许多结构、字符串和数组在复制时不是原子操作,因为它们通常由多个 I/O 大小的元素组成。

    数据项的有效性不依赖于任何其他数据。

    在访问数据时使用关键字“volatile”以避免过时的取消引用。

如果不满足上述任何一项,那么如果您想保证数据一致且有效,则必须使用某种同步。

【讨论】:

谢谢,您的回答非常详细,很有帮助。 如果您使用正确的编译器和硬件内存屏障操作,您可以跳过使用 'volatile'。【参考方案3】:

除了所有出色的响应之外——看看boost::interprocess 库——对于将类似 C++ STL 的容器保存在共享内存中非常方便。它是在 Unixen 上使用 POSIX 共享内存实现的,而不是 SysV,shmem_open(3) 等,您可能也会感兴趣。

【讨论】:

Tkanks,Boost 很有趣。它让我想起了 STL,它比 SysV 更像 C++。【参考方案4】:

如前所述,这是数据完整性问题,而不是段错误。

如果这是一个问题,请使用: 管道 - 这是一个简单的 IPC 系统实现,可能在父级中 6 行代码,在子级中相同

http://tldp.org/LDP/lpg/node11.html

【讨论】:

【参考方案5】:

这里有一个稍微不同的方法:如果你可以保证你的读者/作者不会意外地互相抢占,你就不需要在它们之间进行同步。

例如,您可以保证,在您的 Linux 上,如果您对访问共享内存的所有进程使用调度程序策略 SCHED_FIFO(请参阅 sched_setscheduler(2)),并且它们是否以相同的实时优先级运行并且它们都锁定到同一个 CPU 内核(在多核系统上)。然后,如果阅读器正在执行,它将是唯一执行的进程,直到它选择等待条件或在计时器上休眠。即使写入器从它等待的某些条件中唤醒,在读取期间,调度程序也不会让写入器运行,直到读取器完成。

【讨论】:

【参考方案6】:

我建议使用一个标志来表示访问权限,就像写线程会做标志一样——一旦写完,写线程就可以让它成为标志++,读取线程也做同样的事情。这样可以避免使用 Mutex 和锁定开销。我用过这个并且相信我 flag-- 并且 flag++ 主要是原子的:-)

【讨论】:

以上是关于在不同步的情况下读写 SysV 共享内存(使用信号量、C/C++、Linux)的主要内容,如果未能解决你的问题,请参考以下文章

使用SysV信号量时不一致

Linux下线程同步(带你了解什么是互斥锁死锁读写锁条件变量信号量等)

Boost:shared_memory_object --- 共享内存

如何在不冻结 gui 的情况下运行 QProcess 的同步链?

Linux进程间通信(互斥锁、条件变量、读写锁、文件锁、信号灯)

使用信号量进行共享内存同步