在不调用semctl()的情况下调用semget()后跟semop()是否正确?

时间:2016-11-16 14:46:11

标签: c ipc semaphore

我正在查看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仍会使其不确定。

此代码不正确或我的理解不正确吗?如果我的理解不正确,你能解释一下为什么这段代码是正确的吗?

2 个答案:

答案 0 :(得分:5)

您的理解是正确的,代码不可移植。 POSIX.1-2008 specification of semget不需要初始化信号量:

  

创建后, semid_ds 数据结构与新关联   信号量标识符初始化如下:

     
      
  • 在操作权限结构sem_perm.cuid中,sem_perm.uidsem_perm.cgidsem_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指南”的指南。当您阅读这样的标题时,应该弹出一些非常重要的事情:

  1. 这是一个人对某事的看法 - 这是的做法。具体来说,一个名叫Brian Hall的人的名字是“Beej”。

  2. 它具体说它适用于Unix(实际上是Linux,见下文)。

  3. 如果您阅读Beej's resume(PDF),您会看到他所知道的领域范围内,他不是一个简单的程序员。他是一个修补匠,而修补者会做他们想要的任何事情。这就是为什么他们是聪明的家伙 - 他们犯了很多错误,因此,他们比其他人学到了更多。

  4. 因此,作者可以做任何他想做的事情,他可以在论文中写下他想要的任何东西 - 包括使用平台特定的功能/错误/陷阱/标准/等。有一个part in the article明确告诉您文章的 POSIXey 性质以及编译和运行此代码的平台:

      

    <强> 1.1。观众

         

    如果您了解C或C ++并且使用Unix环境(或支持这些系统调用的其他POSIXey 环境)非常好,那么这些文档适合您。

         

    (...)

         

    <强> 1.2。平台和编译器

         

    本文档中的示例是在Linux下使用gcc 编译的。他们应该在任何可以使用好的Unix编译器的地方编译。

    同样,更多的个人观点:他说他正在使用 Linux gcc 。所以,标题可以改写为:

    使用GCC进行Linux IPC编程的不可靠黑客指南

    这听起来很像Rusty Russell的文章标题! (顺便说一下,另一个修补匠)。无论如何,有这样的标题,你真的会关注POSIX吗?