目录
1. System V IPC
概述
IPC 键和 ftok 函数
ipc_perm 结构
创建与打开 IPC 对象
ipcs 和 ipcrm 命令
计数信号量集
- semget
- semop
- semctl
3. 测试程序
代码实现
- semcreate.c
- semrmid.c
- semsetvalues.c
- semgetvalues.c
- semops.c
运行测试
1. System V IPC
概述
以下三种类型的 IPC 合称为 System V IPC:
System V 信号量
System V 消息队列
System V 共享内存
System V IPC 在访问它们的函数和内核为它们维护的信息上有一些类似点, 主要包括:
IPC 键和 ftok 函数
ipc_perm 结构
创建或打开时指定的用户访问权限
ipcs 和 ipcrm 命令
下表汇总了所有 System V IPC 函数.
信号量 | 消息队列 | 共享内存 | |
---|---|---|---|
头文件 | sys/sem.h | sys/msg.h | sys/shm.h |
创建或打开 IPC 的函数 | semget | msgget | shmget |
控制 IPC 操作的函数 | semctl | msgctl | shmctl |
IPC 操作函数 | semop | msgsnd msgrcv | shmat shmdt |
IPC 键和 ftok 函数
三种类型的 System V IPC 都使用 IPC 键作为它们的标识, IPC 键是一个 key_t 类型的整数, 该类型在 sys/types.h 中定义.
IPC 键通常是由 ftok 函数赋予的, 该函数把一个已存在的路径名 pathname 和一个非 0 整数 id 组合转换成一个 key_t 值, 即 IPC 键.
- #include <sys/ipc.h>
- // 成功返回 IPC 键, 失败返回 - 1
- key_t ftok(const char *pathname, int id);
参数说明:
pathname 在是程序运行期间必须稳定存在, 不能反复创建与删除
id 不能为 0, 可以是正数或者负数
ipc_perm 结构
内核给每个 IPC 对象维护一个信息结构, 即 struct ipc_perm 结构, 该结构及 System V IPC 函数经常使用的常值定义在 sys/ipc.h 头文件中.
- struct ipc_perm
- {
- uid_t uid; //owner's user id
- gid_t gid; //owner's group id
- uid_t cuid; //creator's group id
- gid_t cgid; //creator's group id
- mode_t mode; //read-write permissions
- ulong_t seq; //slot usage sequence number
- key_t key; //IPC key
- };
创建与打开 IPC 对象
创建或打开一个 IPC 对象使用相应的 xxxget 函数, 它们都有两个共同的参数:
参数 key,key_t 类型的 IPC 键
参数 oflag, 用于指定 IPC 对象的读写权限(ipc_perm.mode), 并选择是创建一个新的 IPC 对象还是打开一个已存在的 IPC 对象
对于参数 key, 应用程序有两种选择:
调用 ftok, 给它传 pathname 和 id
指定 key 为 IPC_PRIVATE, 这将保证会创建一个新的, 唯一的 IPC 对象, 但该标志不能用于打开已存在的 IPC 对象, 只能是新建
对于参数 oflag, 如上所述, 它包含读写权限, 创建或打开这两方面信息:
可以指定 IPC_CREAT 标志, 其含义和 Posix IPC 的 O_CREAT 一样
还可以设置为下表所示的常值来指定读写权限
ipcs 和 ipcrm 命令
由于 System V IPC 的三种类型不是以文件系统路径名标识的, 因此无法使用 ls 和 rm 命令查看与删除它们
ipcs 和 ipcrm 分别用于查看与删除系统中的 System V IPC
- usage : ipcs -asmq -tclup
- ipcs [-s -m -q] -i id
- ipcs -h for help.
- usage: ipcrm [ [-q msqid] [-m shmid] [-s semid]
- [-Q msgkey] [-M shmkey] [-S semkey] ... ]
- struct semid_ds
- {
- struct ipc_perm sem_perm;
- struct sem *sem_base; // 指向信号量集的指针
- ushort sem_nsems; // 信号量集中的信号量个数
- time_t sem_otime; // 上一次调用 semop 的时间
- time_t sem_ctime; // 创建时间或上一次以 IPC_SET 调用 semctl 的时间
- };
- struct sem
- {
- ushort_t semval; // 信号量的值
- short sempid; // 上一次成功调用 semop, 或以 SETVAL,SETALL 调用 semctl 的进程 ID
- ushort_t semncnt; // 等待 semval 变为大于当前值的线程数
- ushort_t semzcnt; // 等待 semval 变为 0 的线程数
- };
- semget
- // 成功返回信号量标识符, 失败返回 - 1
- int semget(key_t key, int nsems, int oflag);
- // 成功返回 0, 失败返回 - 1
- int semop(int semid, struct sembuf *ops, size_t nops);
- struct sembuf
- {
- unsigned short sem_num; /* semaphore number */
- short sem_op; /* semaphore operation */
- short sem_flg; /* operation flags */
- };
- // 成功根据 cmd 返回相应的非负值, 失败返回 - 1
- int semctl(int semid, int semnum, int cmd, ... /* union semun arg */);
- union semun
- {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
- };
- semcreate.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define FTOK_FILE "/home/delphi/ftok.file"
- #define FTOK_ID 1
- #define SEM_MODE 0666
- /*
- #define SEM_MODE_OWNER SEM_R | SEM_A
- #define SEM_MODE_GROUP (SEM_R>> 3) | (SEM_A>> 3)
- #define SEM_MODE_OTHER (SEM_R>> 6) | (SEM_A>> 6)
- #define SEM_MODE (SEM_MODE_OWNER | SEM_MODE_GROUP | SEM_MODE_OTHER)
- */
- int main()
- {
- int nsems = 3;
- int oflag = IPC_CREAT | SEM_MODE;
- key_t key = ftok(FTOK_FILE, FTOK_ID);
- int semid = semget(key, nsems, oflag);
- if (semid>= 0)
- {
- printf("semcreate success, semid = %d\n", semid);
- }
- return 0;
- }
- semrmid.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define FTOK_FILE "/home/delphi/ftok.file"
- #define FTOK_ID 1
- int main()
- {
- key_t key = ftok(FTOK_FILE, FTOK_ID);
- int semid = semget(key, 0, 0);
- semctl(semid, 0, IPC_RMID);
- return 0;
- }
- semsetvalues.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define FTOK_FILE "/home/delphi/ftok.file"
- #define FTOK_ID 1
- union semun
- {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
- };
- int main(int argc, char **argv)
- {
- key_t key;
- int semid;
- int nsems;
- unsigned short *semvals;
- union semun arg;
- struct semid_ds seminfo;
- int i;
- /* 打开 semcreate 创建的信号量集 */
- key = ftok(FTOK_FILE, FTOK_ID);
- semid = semget(key, 0, 0);
- /* 获得信号量集中的信号量个数 */
- arg.buf = &seminfo;
- semctl(semid, 0, IPC_STAT, arg);
- nsems = arg.buf->sem_nsems;
- /* 设置信号量集中每个信号量的值 */
- semvals = (unsigned short *)calloc(nsems, sizeof(unsigned short));
- for (i = 0; i <nsems; i++)
- {
- semvals[i] = atoi(argv[i + 1]); // 通过命令行参数分别指定集合中每个信号量的值
- }
- arg.array = semvals;
- semctl(semid, 0, SETALL, arg);
- return 0;
- }
- semgetvalues.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define FTOK_FILE "/home/delphi/ftok.file"
- #define FTOK_ID 1
- union semun
- {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
- };
- int main(int argc, char **argv)
- {
- key_t key;
- int semid;
- int nsems;
- unsigned short *semvals;
- union semun arg;
- struct semid_ds seminfo;
- int i;
- /* 打开 semcreate 创建的信号量集 */
- key = ftok(FTOK_FILE, FTOK_ID);
- semid = semget(key, 0, 0);
- /* 获得信号量集中的信号量个数 */
- arg.buf = &seminfo;
- semctl(semid, 0, IPC_STAT, arg);
- nsems = arg.buf->sem_nsems;
- /* 获得信号量集中每个信号量的值 */
- semvals = (unsigned short *)calloc(nsems, sizeof(unsigned short));
- arg.array = semvals;
- semctl(semid, 0, GETALL, arg);
- for (i = 0; i <nsems; i++)
- {
- printf("semvals[%d] = %d\n", i, semvals[i]);
- }
- return 0;
- }
- semops.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #define FTOK_FILE "/home/delphi/ftok.file"
- #define FTOK_ID 1
- union semun
- {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
- };
- int main(int argc, char **argv)
- {
- key_t key;
- int semid;
- int nsems;
- union semun arg;
- struct semid_ds seminfo;
- struct sembuf *semops;
- int i;
- /* 打开 semcreate 创建的信号量集 */
- key = ftok(FTOK_FILE, FTOK_ID);
- semid = semget(key, 0, 0);
- /* 获得信号量集中的信号量个数 */
- arg.buf = &seminfo;
- semctl(semid, 0, IPC_STAT, arg);
- nsems = arg.buf->sem_nsems;
- /* 对信号量集中的所有信号量进行相同的 semop 操作 */
- semops = (struct sembuf *)calloc(nsems, sizeof(struct sembuf));
- for (i = 0; i <nsems; i++)
- {
- semops[i].sem_num = i;
- semops[i].sem_op = atoi(argv[1]); // 操作类型由命令行参数指定,>0, 0, <0
- semops[i].sem_flg = 0;
- }
- semop(semid, semops, nsems);
- return 0;
- }
来源: https://www.cnblogs.com/songhe364826110/p/11537835.html