1

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

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

谢谢

4

6 回答 6

6

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

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

也许可以在短期内摆脱这个问题,但稍后你发现奇怪的错误。

于 2010-06-10T18:27:26.330 回答
2

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

如果以下条件都为真,则可以避免信号量和互斥锁:

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

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

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

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

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

于 2010-06-10T18:41:08.247 回答
1

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

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

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

于 2010-06-10T18:35:30.903 回答
1

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

于 2010-06-10T19:02:31.043 回答
0

我建议使用一个标志来指示访问权限,就像写入器线程将制作标志一样 - 一旦写入完成,写入器线程可以使其成为标志++,读取器线程也可以这样做。这样可以避免使用 Mutex 和锁定开销。我用过这个并且相信我 flag-- 并且 flag++ 主要是原子的:-)

于 2010-06-11T16:45:36.160 回答
0

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

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

于 2010-06-10T21:27:08.063 回答