我使用SysV共享内存让两个进程相互通信。我不希望代码变得复杂,所以我想知道我是否真的必须使用信号量来同步对共享内存的访问。在我的C / C ++程序中,父进程从共享内存中读取,子进程写入共享内存。我写了两个测试应用程序,看看我是否可以产生某种错误,如分段错误,但我不能(Ubuntu 10.04 64位)。即使两个进程在while循环中写入不停止到同一共享内存也不会产生任何错误。
我希望有人有关于此事的经验,可以告诉我是否真的必须使用信号量来同步访问权限,或者如果我没有同步就可以。
由于
答案 0 :(得分:4)
如果你不使用某种互斥体,那么就会让你自己暴露于与中断相关的奇怪和奇妙的时间错误。
假设您的孩子在被抢占时写入共享内存的过程中途。共享内存现在处于“坏”状态 - 其中一部分涉及子进程的一个状态,其余部分与之前的状态有关 - 并且您的父进程可能会在子进程之前重新激活。然后,你的状态已经破坏了。
你可能能够在短期内摆脱这种情况,但你将稍后发现奇怪的错误。
答案 1 :(得分:1)
如上所述,这是数据完整性的问题,而不是段错误。
如果这是一个问题,请使用: 管道 - 这是一个简单的IPC系统实现,在父级中可能有6行代码,在子级中可能相同
答案 2 :(得分:1)
无论有多少进程尝试“并发”,您都不会通过写入正确映射的内存地址来产生分段错误。同步的目的是维护数据的一致性。
如果满足以下条件,则可以避免信号量和互斥锁:
您只有一个线程写入给定地址。
写入的数据是 atomic - 这意味着它可以在一个I / O操作中传输。像chars和ints这样的简单事物在传输时通常是原子原子。许多结构,字符串和数组在复制时都是 NOT 原子操作,因为它们通常由多个I / O大小的元素组成。
数据项的有效性不依赖于任何其他数据。
在访问数据时使用关键字“volatile”以避免陈旧的解除引用。
如果不满足上述任何一项,那么如果您想保证数据的一致性和有效性,则必须使用某种同步。
答案 3 :(得分:1)
除了所有精细的响应之外 - 看看boost::interprocess
库 - 非常方便将类似C ++ STL的容器保存在共享内存中。它是在Unixen上使用POSIX共享内存实现的,而不是SysV,shmem_open(3)
等,您可能也会感兴趣。
答案 4 :(得分:0)
这是一种稍微不同的方法:如果您可以保证您的读者/作者不意外地相互抢占,则不需要在它们之间进行同步。
例如,您可以保证在Linux上,如果您使用调度程序策略SCHED_FIFO
(请参阅sched_setscheduler(2)
)获取访问共享内存的所有进程以及它们是否正在运行实时优先级并且它们都被锁定到相同的CPU核心(在多核系统上)。然后,如果读取器正在执行,它将是唯一的进程,直到它选择等待条件或睡在计时器上。即使作者从一些条件中醒来它正在等待,在阅读期间,调度程序也不会让作者运行直到读者完成。
答案 5 :(得分:0)
我建议使用一个标志来表示访问权限,就像写入线程将使标志 - 并且一旦写入完成,写入线程可以使其标记为++,Reader线程也会这样做。这样可以避免使用Mutex和锁定开销。我用过这个并且相信我的旗帜 - 而且标志++主要是原子的:-)