0

问题:如何使用 SysV 信号量在两个进程之间进行同步(我们称它们为procAand 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 并准备使用它。

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

是否可以仅使用 sysV 信号量来做到这一点,或者我是否正确地假设我必须求助于其他 IPC 设施,如信号或消息队列才能可靠地设置这些信号量?

4

1 回答 1

0

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

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

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

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

于 2016-02-04T07:23:54.950 回答