linux下进程通讯之信号量集 1.简介 信号量集,就是由多个信号量组成的一个数组。 作为一个整体, 信号量集中所有的信号量使用同一个等待队列。 linux 的信号量集为进程请求多个资源创造了条件。 linux 规定, 当进程的一个操作需要多个共享资源时, 如果只成功获得了其中部分资源, 那么这个请求即告失败, 进程必须立即释放所有已获得资源, 已防止形成死锁。
信号量本质是一个计数器(不设置全局变量是因为进程间是相互独立的), 用于多进程对共享数据对象的读取, 它和管道有所不同, 它不以传送数据为主要目 录, 主要是用来保护共享资源(信号量也属于临界资源), 使得资源在同一时刻只能由一个进程独享。
2.工作原理 信号量只能进行等待和发送信号两种操作, 即 p(申请)和 v(释放)。
(1) p(申请):如果 sv 的值大于 0, 就给他减 1, 如果它的值为 0, 就挂起进程。
(2) v(释放):如果有其他进程等待信号量而被挂起, 就让他恢复运行, 如果没有进程因等待信号量而挂起, 就给他加 1。
在信号量进程 pv 操作时都是为了原子操作(原子操作:单指令的操作, 单条指令的执行时不会被打断的)。
3. 二值信号量 二元信号量(binary semaphore)是最简单的一种锁(互斥锁), 它只有两种状态:占用与非占用。 所以它的引 用计数为 1。
4. 查看系统信号量命令 1.查看信号量组:ipcs -s[wbyq@wbyq 0414work]$ ipcs -s--------- 信号量数组 -----------键 semid 拥有者 权限 nsems 0xd2350092 3 wbyq 666 1 2.查看信号量限制信息:ipcs -ls
[wbyq@wbyq 0414work]$ ipcs -ls--------- 信号量限制 -----------最大数组数量 = 32000每个数组的最大信号量数目 = 32000系统最大信号量数 = 1024000000每次信号量调用最大操作数 = 500信号量最大值=32767 3.查看信号量详细信息:ipcs -s -i
[wbyq@wbyq 0414work]$ ipcs -s -i 3信号量数组 semid=3uid=1000 gid=1000 cuid=1000 cgid=1000模式=0666,访问权限=0666nsems = 1otime = fri apr 29 10:27:21 2022 ctime = fri apr 29 10:25:28 2022 semnum 值 ncount zcount pid 0 1 0 0 13747 4.创建信号量:ipcmk -s
//创建信号量,信号量个数为5个[wbyq@wbyq 0414work]$ ipcmk -s 5 信号量 id:6//查看创建的信号量[wbyq@wbyq 0414work]$ ipcs -s -i 6信号量数组 semid=6uid=1000 gid=1000 cuid=1000 cgid=1000模式=0644,访问权限=0644nsems = 5otime = 未设置 ctime = fri apr 29 14:17:16 2022 semnum 值 ncount zcount pid 0 0 0 0 0 1 0 0 0 0 2 0 0 0 0 3 0 0 0 0 4 0 0 0 0 5.删除信号量:ipcrm -s
//删除信号量6[wbyq@wbyq 0414work]$ ipcs -s 6--------- 信号量数组 -----------键 semid 拥有者 权限 nsems 0xd2350092 3 wbyq 666 1 0xa8132e52 4 wbyq 644 1 0x9416e553 6 wbyq 644 5 [wbyq@wbyq 0414work]$ ipcrm -s 6//删除后结果[wbyq@wbyq 0414work]$ ipcs -s--------- 信号量数组 -----------键 semid 拥有者 权限 nsems 0xd2350092 3 wbyq 666 1 0xa8132e52 4 wbyq 644 1 5.信号量相关函数#include #include #include int semget(key_t key, int nsems, int semflg);函数功能:创建信号量形参:key 键值,ftok产生 nsems 信号量个数,几乎总是为1 semflg 标志 ipc_creat|0666返回值:失败返回-1,成功返回semidint semctl(int semid, int semnum, int cmd, …);函数功能:信号量控制函数形参:semid semget函数返回值 semnum 信号量数组下标,semnum=0表示第一个信号量 cmd 控制命令:setval 初始化信号量值 ipc_rmid 删除信号量,删除只需要前三个参数即可 getval 获取信号量值 可变参数共用体类型(需要自己定义): union semun { int val; /* 要设置的初始值 */ 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) */ };返回值:失败返回-1,成功根据cmd值返回int semop(int semid, struct sembuf *sops, size_t nsops);函数功能: 使用或者释放信号量pv操作形参:semid semget函数返回值 sops 信号量pv操作结构体 struct sembuf sops { unsigned short sem_num; /* 信号量集下标,0表示第一个信号量 */ short sem_op; /*>0则v操作,释放信号量 <0则p操作,使用信号量*/ short sem_flg; / 0 表示默认操作,没有信号量可用就等待。ipc_nowait 表示不等待。 */ }返回值:成功返回信号量标志符,失败返回-1; 6.创建一个信号量示例 (1)创建信号量
#include #include #include #include #include #include #include union semun { int val; /* 信号量值 */ 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[]){ if(argc!=2) { printf(格式:./a.out \n); return 0; } key_t key=ftok(semget.c,1234);//产生键值 if(key==-1) { printf(产生键值失败res=%s\n,strerror(errno)); return 0; } printf(key=%#x\n,key); int semid=semget(key,1,ipc_creat|0666);//创建1个信号量 if(semid==-1) { printf(创建信号量集失败res=%s\n,strerror(errno)); return 0; } printf(semid=%d\n,semid); union semun sem; sem.val=atoi(argv[1]); /*初始化信号量*/ if(semctl(semid,0,setval,sem)) { printf(初始化信号量值失败err=%s\n,strerror(errno)); return 0; } /*获取信号量*/ int val=semctl(semid,0,getval,null); printf(信号量值:%d\n,val); /*通过系统命令查看信号量详细信息*/ char buff[20]; snprintf(buff,sizeof(buff),ipcs -s -i %d,semid); system(buff); return 0;} (2)使用信号量
#include #include #include #include #include #include #include union semun { int val; /* 信号量值 */ 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[]){ if(argc!=2) { printf(格式:./a.out \n); return 0; } key_t key=ftok(semget.c,1234);//产生键值 if(key==-1) { printf(产生键值失败res=%s\n,strerror(errno)); return 0; } printf(key=%#x\n,key); int semid=semget(key,1,ipc_creat|0666);//创建1个信号量 if(semid==-1) { printf(创建信号量集失败res=%s\n,strerror(errno)); return 0; } printf(semid=%d\n,semid); /*获取信号量*/ int val=semctl(semid,0,getval,null); printf(信号量值:%d\n,val); /*pv操作*/ struct sembuf sops= { .sem_num=0,//信号量下标 .sem_op=atoi(argv[1]), .sem_flg=0//阻塞等待 }; int ret=semop(semid,&sops,1); printf(ret=%d\n,ret); /*获取信号量*/ val=semctl(semid,0,getval,null); printf(信号量值:%d\n,val); return 0;} 7.创建多个信号量 (1)创建多个信号量
#include #include #include #include #include #include #include union semun { int val; /* 信号量值 */ 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[]){ if(argc!=4) { printf(格式:./a.out \n); return 0; } key_t key=ftok(semget.c,1234);//产生键值 if(key==-1) { printf(产生键值失败res=%s\n,strerror(errno)); return 0; } printf(key=%#x\n,key); int semid=semget(key,3,ipc_creat|0666);//创建3个信号量 if(semid==-1) { printf(创建信号量集失败res=%s\n,strerror(errno)); return 0; } printf(semid=%d\n,semid); union semun sem[3]; sem[0].val=atoi(argv[1]);//初始化第一个信号量 sem[1].val=atoi(argv[2]);//初始化第二个信号量 sem[2].val=atoi(argv[3]);//初始化第三个信号量 int i=0; for(i=0;i<3;i++) { /*初始化信号量*/ if(semctl(semid,i,setval,sem[i])) { printf(初始化信号量值失败err=%s\n,strerror(errno)); return 0; } /*获取信号量*/ int val=semctl(semid,i,getval,null); printf(第%d个信号量值:%d\n,i,val); } /*通过系统命令查看信号量详细信息*/ system(ipcs -s); return 0;} (2)使用多个信号量
#include #include #include #include #include #include #include union semun { int val; /* 信号量值 */ 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[]){ if(argc!=2) { printf(格式:./a.out \n); return 0; } key_t key=ftok(semget.c,1234);//产生键值 if(key==-1) { printf(产生键值失败res=%s\n,strerror(errno)); return 0; } printf(key=%#x\n,key); int semid=semget(key,3,ipc_creat|0666);//创建3个信号量 if(semid==-1) { printf(创建信号量集失败res=%s\n,strerror(errno)); return 0; } printf(semid=%d\n,semid); int i=0; /*获取信号量*/ for(i=0;i<3;i++) { /*获取信号量*/ int val=semctl(semid,i,getval,null); printf(第%d个信号量值:%d\n,i,val); } /*pv操作*/ struct sembuf sops[3]= { { .sem_num=0,//信号量下标 .sem_op=atoi(argv[1]), .sem_flg=0//阻塞等待 }, { .sem_num=1,//信号量下标 .sem_op=atoi(argv[1]), .sem_flg=0//阻塞等待 }, { .sem_num=2,//信号量下标 .sem_op=atoi(argv[1]), .sem_flg=0//阻塞等待 } }; int ret=semop(semid,sops,3);//一次使用3个信号量 printf(ret=%d\n,ret); /*获取信号量*/ /*获取信号量*/ for(i=0;i<3;i++) { /*获取信号量*/ int val=semctl(semid,i,getval,null); printf(第%d个信号量值:%d\n,i,val); } return 0;} (3)运行效果
忘记Mysql用户密码怎么办
激光切割厚板的调试方法与技巧
苹果推出新服务:可将存储照片和视频转移到Google相册
集成电路常见的元器件
是雷军的年度演讲比较吸引你,还是小米的新品更为吸引你呢?
Linux下进程通讯之信号量集
iOS10.2越狱为何迟迟不来?苹果又是为何要发布iOS10.3
皮肤电活动测量系统的设计、开发与评估
纽劢科技以基于深度学习的多传感融合方案打造量产级自动驾驶
手机如何才能远程控制电脑
银灿科技三段式防写技术,保护你的U盘不受病毒侵害
焊接机器人及系统介绍(焊接机器人系统组成和编程方法及发展趋势)
电动机的功率及转速
小布助手,身入大千世界
医疗行业新型诊断硬件开发商Exo在新一轮融资中筹集4000万美元
音频均衡器电路的工作原理解析
基于一种具有极低脱落电压LDO的白光LED恒流驱动芯片设计
小米Mi A2 Lite现已进入常规软件更新的最后一年
Linux中的管道和命名管道介绍
Lime Microsystems射频收发器芯片已被GWT通