SEMGET - Linux手册页
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/。