【发布时间】:2016-05-09 00:41:43
【问题描述】:
问题:如何使用 SysV 信号量在两个进程之间进行同步(我们称它们为 procA 和 procB),假设它们都独立于 shell 运行(它们都不是由 fork/ 产生的) exec 组合)并且信号量必须由这两个进程之一创建。
引用man semget:
新创建的集合中的信号量值是 不定。 (POSIX.1-2001 在这一点上是明确的。)虽然 Linux 和许多其他实现一样,初始化信号量 值为 0,可移植应用程序不能依赖此:它 应该将信号量显式初始化为所需的值。
假设我们想要编写仅依赖于 POSIX 保证而不依赖于 Linux 特定保证的可移植代码。很好,因此不可能原子地创建信号量集并对其进行初始化。这必须通过两个单独的调用来完成。
因此,为procA 创建信号量集的代码如下所示:
int sem_id = semget(key, nsems, IPC_CREAT | S_IRWXU);
procB 也一样——这样,无论哪个进程碰巧第一次需要信号量,它也会创建它们;否则,它只是获取信号量集的 ID 并准备使用它。
需要初始化时问题开始出现。初始化指令当然是semctl 和SETALL——但是: • 初始化应该只进行一次,并且 • 初始化应该在使用信号量之前完成。这当然可以通过……信号量来强制执行,但不幸的是这样的解决方案是递归的:我们需要信号量来设置信号量,而信号量本身也需要设置信号量等等。
是否可以仅使用 sysV 信号量来做到这一点,或者我是否正确地假设我必须求助于其他 IPC 设施,如信号或消息队列才能可靠地设置这些信号量?
【问题讨论】:
-
稍后在
man semget中说:“可以使用 semctl(2) SETVAL 或 SETALL 操作完成初始化。如果多个对等方不知道谁将是第一个初始化设置,检查 semctl(2) IPC_STAT 操作检索的关联数据结构中的非零 sem_otime 可用于避免竞争。" -
@Kenney 是的。所以我们有一个
if。而if仍然需要一些努力来确保它是原子的。 -
@Kenney 我的意思是,我们必须确保在检查
sem_otime是否为非零和初始化信号量之间没有其他进程与同一组混淆。不知何故,我不知道该怎么做。 -
是的,我明白你的意思。它看起来坏了;-)
-
也许在
semget上指定IPC_CREAT | IPC_EXCL可以解决问题:如果信号量存在,它将返回EEXISTS。没有得到错误的调用者进行初始化,得到错误的调用者在没有IPC_CREAT的情况下执行另一个semget(并且不初始化它)。
标签: concurrency initialization posix semaphore sysv-ipc