SEMGET - Linux手册页

时间:2019-08-20 17:59:19  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-04-11

名称

semget-获取System V信号量集标识符

语法

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t键,int nsems,int semflg);

说明

semget()系统调用返回与自变量键关联的System V信号量集标识符。它既可以用于获取先前创建的信号量集的标识符(当semflg为零且键的值不为IPC_PRIVATE时),也可以用于创建新的信号量集。

如果key的值为IPC_PRIVATE或没有与该key相关联的现有信号量集,并且在semflg中指定了IPC_CREAT,则会创建一组新的nsems信号量。

如果semflg同时指定了IPC_CREAT和IPC_EXCL,并且密钥的信号集已存在,则semget()失败,并且errno设置为EEXIST。 (这类似于组合open_(2)的O_CREAT | O_EXCL的效果。)

创建后,参数semflg的最低9位定义了信号量集的权限(所有者,组和其他人)。这些位与open(2)的mode参数具有相同的格式和相同的含义(尽管执行许可权对信号量没有意义,而写许可权是指更改信号量值的许可权)。

创建新的信号量集时,semget()初始化该集的关联数据结构semid_ds(请参见semctl(2)),如下所示:

*
sem_perm.cuid和sem_perm.uid设置为调用进程的有效用户ID。
*
sem_perm.cgid和sem_perm.gid设置为调用进程的有效组ID。
*
sem_perm.mode的最低9位设置为semflg的最低9位。
*
sem_nsems设置为nsems的值。
*
sem_otime设置为0。
*
sem_ctime设置为当前时间。

未创建信号量集时,参数nsems可以为0(无关紧要)。否则,nsems必须大于0且小于或等于每个信号量集(SEMMSL)的最大信号量。

如果信号集已存在,则将验证权限。

返回值

如果成功,则返回值将是信号量集标识符(非负整数),否则返回-1,其中errno指示错误。

错误说明

失败时,errno将设置为以下之一:

EACCES
密钥有一个信号集,但是调用进程没有访问该集的权限,并且在管理其IPC名称空间的用户名称空间中不具有CAP_IPC_OWNER功能。
EEXIST
在semflg中指定了IPC_CREAT和IPC_EXCL,但是密钥的信号量集已经存在。
EINVAL
nsems小于0或大于每个信号量集(SEMMSL)的信号量限制。
EINVAL
对应于key的信号量集已经存在,但是nsems大于该键集中的信号量。
ENOENT
没有为键设置信号量,并且semflg未指定IPC_CREAT。
ENOMEM
必须创建一个信号集,但是系统没有足够的内存来存储新的数据结构。
ENOSPC
必须创建一个信号集,但是将超出最大信号集集(SEMMNI)的系统限制或系统范围内最大信号量(SEMMNS)。

遵循规范

SVr4,POSIX.1-2001。

备注

在Linux或任何版本的POSIX上,都不需要包含和。但是,一些旧的实现需要包含这些头文件,并且SVID也记录了这些头文件。打算移植到这样的旧系统的应用程序可能需要包括这些头文件。

IPC_PRIVATE不是标志字段,而是key_t类型。如果将此特殊值用于键,则系统调用将忽略除最低有效9位之外的所有semflg并创建一个新的信号量集(成功时)。

Semaphore initialization

新创建的集合中的信号量的值不确定。 (尽管POSIX.1-2008指出该标准的未来版本可能要求将信号量初始化为0的实现,但是POSIX.1-2001和POSIX.1-2008在这一点上是明确的。)在实现中,将信号量值初始化为0,可移植的应用程序不能依赖于此:它应将信号量显式初始化为所需的值。

可以使用semctl(2)SETVAL或SETALL操作完成初始化。如果多个对等节点不知道谁将是第一个初始化该集合的节点,则可以使用semctl(2)IPC_STAT操作检索的关联数据结构中检查非零的sem_otime来避免竞争。

Semaphore limits

信号量集资源的以下限制会影响semget()调用:

SEMMNI
系统范围内信号灯集的数量限制。在3.19之前的Linux系统上,此限制的默认值为128。从Linux 3.19开始,默认值为32,000。在Linux上,可以通过/ proc / sys / kernel / sem的第四个字段读取和修改此限制。
SEMMSL
每个信号灯ID的最大信号灯数。在3.19版之前的Linux系统上,此限制的默认值为250。自Linux 3.19起,默认值为32,000。在Linux上,可以通过/ proc / sys / kernel / sem的第一个字段读取和修改此限制。
SEMMNS
系统范围内的信号量限制:与策略有关(在Linux上,可以通过/ proc / sys / kernel / sem的第二个字段读取和修改此限制)。请注意,系统范围内的信号量的数量也受到SEMMSL和SEMMNI乘积的限制。

BUGS

名称选择IPC_PRIVATE可能是不幸的,IPC_NEW将更清楚地显示其功能。

示例

下面显示的程序使用semget()来创建新的信号量集或检索现有集合的ID。它使用ftok(3)生成semget()的密钥。前两个命令行参数用作ftok(3)的路径名和proj_id参数。第三个命令行参数是一个整数,它指定semget()的nsems参数。命令行选项可用于为semget()的调用指定IPC_CREAT(-c)和IPC_EXCL(-x)标志。该程序的用法如下所示。

我们首先创建两个文件,这些文件将用于使用ftok(3)生成密钥,使用这些文件创建两个信号集,然后使用ipcs(1)列出这些集:

$ touch mykey mykey2
$ ./t_semget -c mykey p 1
ID = 9
$ ./t_semget -c mykey2 p 2
ID = 10
$ ipcs -s

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x7004136d 9          mtk        600        1
0x70041368 10         mtk        600        2

接下来,我们演示当给semctl(2)相同的密钥(由ftok(3)的相同参数生成)时,它返回已经存在的信号量集的ID:

$ ./t_semget -c mykey p 1
ID = 9

最后,我们演示了当ftok(3)被赋予具有相同inode编号的不同路径名参数时可能发生的冲突:

$ ln mykey link
$ ls -i1 link mykey
2233197 link
2233197 mykey
$ ./t_semget link p 1       # Generates same key as aqmykeyaq
ID = 9

Program source

/* t_semget.c

   Licensed under GNU General Public License v2 or later.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void
usage(const char *pname)
{
    fprintf(stderr, "Usage: %s [-cx] pathname proj-id num-sems\n",
            pname);
    fprintf(stderr, "    -c           Use IPC_CREAT flag\n");
    fprintf(stderr, "    -x           Use IPC_EXCL flag\n");
    exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
    int semid, nsems, flags, opt;
    key_t key;

    flags = 0;
    while ((opt = getopt(argc, argv, "cx")) != -1) {
        switch (opt) {
        case aqcaq: flags |= IPC_CREAT;   break;
        case aqxaq: flags |= IPC_EXCL;    break;
        default:  usage(argv[0]);
        }
    }

    if (argc != optind + 3)
        usage(argv[0]);

    key = ftok(argv[optind], argv[optind + 1][0]);
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    nsems = atoi(argv[optind + 2]);

    semid = semget(key, nsems, flags | 0600);
    if (semid == -1) {
        perror("semget");
        exit(EXIT_FAILURE);
    }

    printf("ID = %d\n", semid);

    exit(EXIT_SUCCESS);
}

另外参见

semctl(2),semop(2),ftok(3),功能(7),sem_overview(7),sysvipc(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/