【发布时间】:2017-03-30 19:45:22
【问题描述】:
我正在查看Beej's Guide to Unix IPC 中的信号量示例程序。
示例程序包含以下信号量初始化代码。我只发布一个与问题相关的 sn-p。要查看完整代码,请访问我上面提供的链接。
/*
** initsem() -- more-than-inspired by W. Richard Stevens' UNIX Network
** Programming 2nd edition, volume 2, lockvsem.c, page 295.
*/
int initsem(key_t key, int nsems) /* key from ftok() */
{
int i;
union semun arg;
struct semid_ds buf;
struct sembuf sb;
int semid;
semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
if (semid >= 0) { /* we got it first */
sb.sem_op = 1; sb.sem_flg = 0;
arg.val = 1;
printf("press return\n"); getchar();
for(sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) {
/* do a semop() to "free" the semaphores. */
/* this sets the sem_otime field, as needed below. */
if (semop(semid, &sb, 1) == -1) {
int e = errno;
semctl(semid, 0, IPC_RMID); /* clean up */
errno = e;
return -1; /* error, check errno */
}
}
这是我无法理解的。一旦semget() 创建信号量并使用有效的信号量 ID 成功返回,信号量本身就未初始化并处于不确定状态。 semget 的手册页证实了这一点。
信号量初始化
新创建的集合中的信号量值是不确定的。 (POSIX.1-2001 和 POSIX.1-2008 在这一点上是明确的,尽管 POSIX.1-2008 指出该标准的未来版本可能 需要一个实现来将信号量初始化为 0。)尽管 Linux 与许多其他实现一样,将信号量值初始化为 0,但可移植应用程序不能依赖此:它 应该将信号量显式初始化为所需的值。
可以使用 semctl(2) SETVAL 或 SETALL 操作来完成初始化。在多个对等点不知道谁将是第一个初始化集合的情况下,检查关联的非零 sem_otime semctl(2) IPC_STAT 操作检索的数据结构可用于避免竞争。
但是在上面的代码中semctl() 没有被调用来初始化信号量。相反,semop() 是用sem_op = 1 调用的,根据semop 的手册页,它会执行以下操作。
如果 sem_op 是一个正整数,则操作将该值添加到信号量值 (semval)。此外,如果为此操作指定了 SEM_UNDO,则系统会从 sem_op 中减去 此信号量的信号量调整 (semadj) 值。这个操作总是可以进行的——它从不强制线程等待。调用进程必须对信号量集具有更改权限。
但如果没有初始化,semval 是不确定的。所以添加1 到它仍然是不确定的。
此代码不正确还是我的理解不正确?如果我的理解不正确,请您解释一下为什么这段代码是正确的?
【问题讨论】: