【问题标题】:How to reliably initialize IPC semaphores?如何可靠地初始化 IPC 信号量?
【发布时间】:2016-05-09 00:41:43
【问题描述】:

问题:如何使用 SysV 信号量在两个进程之间进行同步(我们称它们为 procAprocB),假设它们都独立于 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 并准备使用它。

需要初始化时问题开始出现。初始化指令当然是semctlSETALL——但是: • 初始化应该只进行一次,并且 • 初始化应该在使用信号量之前完成。这当然可以通过……信号量来强制执行,但不幸的是这样的解决方案是递归的:我们需要信号量来设置信号量,而信号量本身也需要设置信号量等等。

是否可以仅使用 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


【解决方案1】:

根据我的经验,这在现实世界中不是问题。我将 IPC 创建和初始化放在一个单独的程序中,该程序在运行任何客户端程序之前由系统启动脚本调用。 IPC 资源永远不会被删除,只有在机器重启后才会消失。

如果我必须动态创建资源,我会让创建者程序以单独的用户身份启动,并以所有者权限创建资源。然后它会对其进行初始化,最后授予客户端用户权限,然后退出。

客户端只需在 ENOENT 或 EACCES 上重试,可能会使用 nanosleep。

不过,我可能只使用 POSIX 信号量,因为 sem_open(3) 让您指定 O_EXCL 和初始值。旧的 Sys V 习惯很难改掉。

【讨论】:

    猜你喜欢
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多