我正在通过Beej的Unix IPC指南中的信号量示例程序.
示例程序包含以下信号量初始化代码.我只发布一个与问题相关的片段.要查看完整代码,请访问我上面提供的链接.
/*
** 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 */
}
}
Run Code Online (Sandbox Code Playgroud)
这是我无法理解的.一旦semget()创建信号量并使用有效的信号量ID成功返回,信号量本身就是未初始化且处于不确定状态.这可以通过手册页确认semget.
信号量初始化
新创建的集合中的信号量值是不确定的.(POSIX.1-2001和POSIX.1-2008在这一点上是明确的,尽管POSIX.1-2008指出该标准的未来版本可能需要一个实现来将信号量初始化为0.)虽然Linux,像许多其他实现,将信号量值初始化为0,便携式应用程序不能依赖于此:它应该将信号量显式初始化为所需的值.
可以使用semctl(2)SETVAL或SETALL操作完成初始化.在多个对等体不知道谁将是第一个初始化该集合的情况下,检查由semctl(2)IPC_STAT操作检索的关联数据结构中的非零sem_otime可以用于避免竞争.
但是在上面的代码semctl()中没有调用来初始化信号量.相反,semop()用sem_op= 调用1,根据手册页进行semop以下操作.
如果sem_op是正整数,则操作会将此值添加到信号量值(semval).此外,如果为此操作指定了SEM_UNDO,系统将从此信号量的信号量调整(semadj)值中减去值sem_op.此操作始终可以继续 - 它永远不会强制线程等待.调用进程必须对信号量集具有alter权限.
但没有初始化,semval是不确定的.所以添加1它仍然使它不确定.
这段代码不正确还是我的理解不正确?如果我的理解不正确,你能解释一下为什么这段代码是正确的吗?
您的理解是正确的,代码不可移植.该的POSIX.1-2008规范semget不需要旗语进行初始化:
在创建时,与新信号量标识符相关联的semid_ds数据结构初始化如下:
在该操作权限结构
sem_perm.cuid,sem_perm.uid,sem_perm.cgid,和sem_perm.gid应分别设置为有效用户ID和有效组ID,调用进程的.低位9位
sem_perm.mode应设置为低位9位semflg.变量
sem_nsems应设置为值nsems.变量
sem_otime应设置为0,并sem_ctime应设置为当前时间,如IPC一般说明中所述.不需要初始化与集合中的每个信号量相关联的数据结构.的
semctl()与该命令SETVAL或SETALL功能可用于初始化每个信号量.