XSI进程间通信---信号量
来源:互联网 发布:2015年各省地税数据 编辑:程序博客网 时间:2024/05/18 12:44
1. 基本特点
1) 相当于计数器,用于限制多个进程对有限共享资源的访问。
2) 多个进程获取有限共享资源的操作模式
A. 测试控制该资源的信号量;
B. 若信号量大于0,则进程可以使用该资源, 为了表示此进程已获得该资源,需将信号量减1;
C. 若信号量等于0,则进程休眠等待该资源, 直到信号量大于0,进程被唤醒,执行步骤A;
D. 当某进程不再使用该资源时,信号量增1, 正在休眠等待该资源的其它进程将被唤醒。
3)内核维护一个semid_ds结构体
struct semid_ds { struct ipc_perm sem_perm; // 权限信息 time_t sem_otime; // 上次执行 semop 的时间 time_t sem_ctime; // 最后更新时间 unsigned short sem_nsems; // 在信号量集合里的索引};
struct ipc_perm { key_t __key; // 键值 uid_t uid; // 有效属主ID gid_t gid; // 有效属组ID uid_t cuid; // 有效创建者ID gid_t cgid; // 有效创建组ID unsigned short mode; // 权限字 unsigned short __seq; // 序列号};
2. 常用函数
1) 创建/获取信号量
int semget (key_t key, int nsems, int semflg);
A. 该函数以key参数为键值创建一个信号量集合 (nsems参数表示集合中的信号量数 ,或获取已有的信号量集合(nsems取0)。
B. semflg取值:0 - 获取,不存在即失败。
IPC_CREAT - 创建,不存在即创建,已存在即获取,除非...
IPC_EXCL - 排斥,已存在即失败。
C. 成功返回信号量集合标识semid,失败返回-1。
2) 操作信号量:它的作用是改变信号量的值
int semop (int semid, struct sembuf* sops,unsigned nsops);
struct sembuf { unsigned short sem_num; // 信号量下标 short sem_op; // 操作数 short sem_flg; // 操作标记};
A. 该函数对semid参数所标识的信号量集合中, 由sops参数所指向的包含nsops个元素的, 结构体数组中的每个元素,依次执行如下操作:
a) 若sem_op大于0, 则将其加到第sem_num个信号量的计数值上,以表示对资源的释放;
b) 若sem_op小于0,则从第sem_num个信号量的计数值中减去其绝对值,以表示对资源的获取;
c) 若第sem_num个信号量的计数值不够减(信号量不能为负), 则此函数会阻塞,直到该信号量够减为止,以表示对资源的等待;
d) 若sem_flg包含IPC_NOWAIT位,则当第sem_num个信号量的计数值不够减时, 此函数不会阻塞,而是返回-1,errno为EAGAIN,以便在等待资源的同时还可做其它处理;
e) 若sem_op等于0,则直到第sem_num个信号量的计数值为0时才返回, 除非sem_flg包含IPC_NOWAIT位。
B. 成功返回0,失败返回-1。
3) 销毁/控制信号量
int semctl (int semid, int semnum, int cmd);int semctl (int semid, int semnum, int cmd,union semun arg);
函数描述:semctl() 在 semid 标识的信号量集上,或者该集合的第 semnum 个信号量上执行 cmd 指定的控制命令。(信号量集合索引起始于零。)
A. senum :信号集的索引,用来存取信号集内的某个信号
union semun { int val; // SETVAL使用的值 struct semid_ds *buf; // IPC_STAT、IPC_SET 使用缓存区 unsigned short *array; // GETALL,、SETALL 使用的数组 struct seminfo *__buf; // IPC_INFO(Linux特有) 使用缓存区 };
B. cmd取值:
IPC_STAT - 获取信号量集合的属性,通过arg.buf输出。
IPC_SET - 设置信号量集合的属性,通过arg.buf输入,仅三个属性可设置
IPC_RMID - 立即删除信号量集合。 此时所有阻塞在对该信号量集合的,semop函数调用,都会立即返回失败,errno为EIDRM。
GETALL - 获取信号量集合中每个信号量的计数值, 通过arg.array输出。
SETALL - 设置信号量集合中每个信号量的计数值,通过arg.array输入。
GETVAL - 获取信号量集合中, 第semnum个信号量的计数值, 通过返回值输出。
SETVAL - 设置信号量集合中,第semnum个信号量的计数值, 通过arg.val输入。
注意:只有针对信号量集合中具体某个信号量的操作,才会使用semnum参数。针对整个信号量集合的操作,会忽略semnum参数。
C. 成功返回值因cmd而异,失败返回-1。
3. 编程模型
这里模拟一个简单的借书还书的案例:
#include <stdio.h>#include <errno.h>#include <sys/sem.h>int pleft (int semid) {int val = semctl (semid, 0, GETVAL);if (val == -1) {perror ("semctl");return -1;}printf ("还剩%d册。\n", val);return 0;}int main (void) {printf ("创建信号量...\n");key_t key = ftok (".", 100);if (key == -1) {perror ("ftok");return -1;}int semid = semget (key, 1, 0644 | IPC_CREAT | IPC_EXCL);if (semid == -1) {perror ("semget");return -1;}printf ("初始信号量...\n");if (semctl (semid, 0, SETVAL, 5) == -1) {perror ("semctl");return -1;}int quit = 0;while (! quit) {printf ("--------\n");printf ("三国演义\n");printf ("--------\n");printf ("[1] 借阅\n");printf ("[2] 归还\n");printf ("[0] 退出\n");printf ("--------\n");printf ("请选择:");int sel = -1;scanf ("%d", &sel);switch (sel) {case 0:quit = 1;break;case 1: {//printf ("请稍候...\n");struct sembuf sops = {0, -1, /*0*/IPC_NOWAIT};if (semop (semid, &sops, 1) == -1) {if (errno == EAGAIN) {printf ("暂时无书,下回再试。\n");break;}else {perror ("semop");return -1;}}printf ("恭喜恭喜,借阅成功。\n");pleft (semid);break;}case 2: {struct sembuf sops = {0, 1, 0};if (semop (semid, &sops, 1) == -1) {perror ("semop");return -1;}printf ("好借好还,再借不难。\n");pleft (semid);break;}default:printf ("无效选择!\n");scanf ("%*[^\n]");scanf ("%*c");break;}}printf ("销毁信号量...\n");if (semctl (semid, 0, IPC_RMID) == -1) {perror ("semctl");return -1;}printf ("大功告成!\n");return 0;}
#include <stdio.h>#include <errno.h>#include <sys/sem.h>int pleft (int semid) {int val = semctl (semid, 0, GETVAL);if (val == -1) {perror ("semctl");return -1;}printf ("还剩%d册。\n", val);return 0;}int main (void) {printf ("获取信号量...\n");key_t key = ftok (".", 100);if (key == -1) {perror ("ftok");return -1;}int semid = semget (key, 0, 0);if (semid == -1) {perror ("semget");return -1;}int quit = 0;while (! quit) {printf ("--------\n");printf ("三国演义\n");printf ("--------\n");printf ("[1] 借阅\n");printf ("[2] 归还\n");printf ("[0] 退出\n");printf ("--------\n");printf ("请选择:");int sel = -1;scanf ("%d", &sel);switch (sel) {case 0:quit = 1;break;case 1: {//printf ("请稍候...\n");struct sembuf sops = {0, -1, /*0*/IPC_NOWAIT};if (semop (semid, &sops, 1) == -1) {if (errno == EAGAIN) {printf ("暂时无书,下回再试。\n");break;}else {perror ("semop");return -1;}}printf ("恭喜恭喜,借阅成功。\n");pleft (semid);break;}case 2: {struct sembuf sops = {0, 1, 0};if (semop (semid, &sops, 1) == -1) {perror ("semop");return -1;}printf ("好借好还,再借不难。\n");pleft (semid);break;}default:printf ("无效选择!\n");scanf ("%*[^\n]");scanf ("%*c");break;}}printf ("大功告成!\n");return 0;}
也可以结合这篇博文来一起学习点击打开链接
- XSI进程间通信---信号量
- XSI进程间通信---共享内存
- XSI进程间通信---消息队列
- 进程间通信之XSI IPC
- 进程间通信 信号量
- 进程间通信--信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 【进程间通信】信号量
- 进程间通信----信号量
- 进程间通信:信号量
- 进程间通信-信号量
- 进程间通信-信号量
- 进程间通信--信号量
- 进程间通信--信号量
- 进程间通信---->信号量
- 进程间通信-信号量
- 第74讲:从Spark源码的角度思考Scala中的模式匹配学习笔记
- 正则表达式模板大全
- 程序设计策略(设计一款APP的步骤)
- python爬虫(三)--Python的set()
- thinkpad s3 安装win8 kali双系统笔记
- XSI进程间通信---信号量
- struts2中jsp页面向后台传值的三种方法
- 指针详解
- nefu oj 986 林大的入学体检(运算符重载在排序中的运用)
- 我博客搬家了
- javascript_BOM&DOM&JSON
- losersaver硕士待遇杂谈
- nginx配置
- 计数排序