我正在查看Beej's Guide to 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 */
}
}
这是我无法理解的。一旦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)值。此操作始终可以继续 - 它永远不会强制线程等待。调用进程必须对信号量集具有alter权限。
但是没有初始化,semval
是不确定的。因此,向其添加1
仍会使其不确定。
此代码不正确或我的理解不正确吗?如果我的理解不正确,你能解释一下为什么这段代码是正确的吗?
答案 0 :(得分:5)
您的理解是正确的,代码不可移植。 POSIX.1-2008 specification of semget
不需要初始化信号量:
创建后, semid_ds 数据结构与新关联 信号量标识符初始化如下:
在操作权限结构
sem_perm.cuid
中,sem_perm.uid
,sem_perm.cgid
和sem_perm.gid
应设置为 呼叫的有效用户ID和有效组ID 过程
sem_perm.mode
的低位9位应设置为semflg
的低位9位。变量
sem_nsems
应设置为nsems
的值。变量
sem_otime
应设置为0,sem_ctime
应设置为当前时间,如IPC General Description中所述。与集合中的每个信号量关联的数据结构无需初始化。使用命令SETVAL或
semctl()
函数 SETALL可用于初始化每个信号量。
答案 1 :(得分:2)
这不应该是一个答案,但它不会适应评论,因为它不断增长......
Tim answers您的问题在技术领域非常好(这就是SO的全部内容)。但是,今晚我感觉 philosophical ,我认为你怀疑的来源可能更微妙:我认为你的问题更多的是关于上下文和作者而不是它是关于代码的。
根据您发布的内容:
信号量初始化
新创建的集合中的信号量值是不确定的。(POSIX.1-2001和POSIX.1-2008在这一点上是明确的,尽管POSIX.1-2008指出了该标准的未来版本可能需要一个实现来将信号量初始化为0.)虽然Linux与许多其他实现一样,将信号量值初始化为0,但是可移植应用程序不能依赖于此:它应该显式地将信号量初始化为期望值。
您正在关注一个标题为“ Beej的Unix IPC指南”的指南。当您阅读这样的标题时,应该弹出一些非常重要的事情:
这是一个人对某事的看法 - 这是他的做法。具体来说,一个名叫Brian Hall的人的名字是“Beej”。
它具体说它适用于Unix(实际上是Linux,见下文)。
如果您阅读Beej's resume(PDF),您会看到他所知道的领域范围内,他不是一个简单的程序员。他是一个修补匠,而修补者会做他们想要的任何事情。这就是为什么他们是聪明的家伙 - 他们犯了很多错误,因此,他们比其他人学到了更多。
因此,作者可以做任何他想做的事情,他可以在论文中写下他想要的任何东西 - 包括使用平台特定的功能/错误/陷阱/标准/等。有一个part in the article明确告诉您文章的 POSIXey 性质以及编译和运行此代码的平台:
<强> 1.1。观众
如果您了解C或C ++并且使用Unix环境(或支持这些系统调用的其他POSIXey 环境)非常好,那么这些文档适合您。
(...)
<强> 1.2。平台和编译器
本文档中的示例是在Linux下使用gcc 编译的。他们应该在任何可以使用好的Unix编译器的地方编译。
同样,更多的个人观点:他说他正在使用 Linux 和 gcc 。所以,标题可以改写为:
这听起来很像Rusty Russell的文章标题! (顺便说一下,另一个修补匠)。无论如何,有这样的标题,你真的会关注POSIX吗?