当前位置: 首页 > news >正文

学习记录——day28 信号量集

目录

一、信号量集

1、信号量集的API函数接口

二、 将信号量集函数再次封装

 1、sem.h

2、sem.c

三、使用信号量集完成共享内存的进程同步

 1、发送端

2、接收端


一、信号量集

        信号量集,其实就是无名信号量的集合,主要用于完整多个进程间的同步问题.。

        使用 semget 函数申请信号量集时,需指定申请的信号量的数量,函数会对信号量从零开始编号;对信号量进行初始化则、删除等操作需要使用 semctl 函数;申请和释放信号量时需指定信号量编号使用的时 semop 函数。

        由于直接使用函数库提供的函数操作繁琐,使用不方便,所以对信号量集相关函数进行再次封装,以便使用。

1、信号量集的API函数接口

1、创建一个信号量集
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semget(key_t key, int nsems, int semflg);
       功能:创建信号灯集
       参数1:用于创建信号量集的key值,可以是IPC_PRIVATE,也可以由ftok创建出来
       参数2:创建的信号灯集中的信号量的个数
       参数3:创建的标识
                IPC_CREAT:表示本次操作要创建一个信号量集,如果该key值对应的信号量集已经存在,则直接打开该信号量集对象
                IPC_EXCL:表示本次确保要创建一个新的信号量集,如果该信号量集已经存在,则该函数报错,错误码为EEXIST
                创建文件的权限,也在该参数中,使用位或连接
        返回值:成功返回创建出来的共享内存的id,失败返回-1并置位错误码

2、信号量集的控制函数
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semctl(int semid, int semnum, int cmd, ...);
       功能:信号量集的控制函数
       参数1:信号量集的id
       参数2:要控制的信号灯集中的信号灯的编号,编号从0开始的
       参数3:控制指令
           IPC_RMID:删除信号灯集,此时参数4可以省略不写,参数2被忽略
           IPC_STAT\IPC_SET:获取或设置信号灯集的属性
           struct semid_ds {
               struct ipc_perm sem_perm;  /* Ownership and permissions */
               time_t          sem_otime; /* Last semop time */
               time_t          sem_ctime; /* Last change time */
               unsigned long   sem_nsems; /* No. of semaphores in set */
           };

       The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):

           struct ipc_perm {
               key_t          __key; /* Key supplied to semget(2) */
               uid_t          uid;   /* Effective UID of owner */
               gid_t          gid;   /* Effective GID of owner */
               uid_t          cuid;  /* Effective UID of creator */
               gid_t          cgid;  /* Effective GID of creator */
               unsigned short mode;  /* Permissions */
               unsigned short __seq; /* Sequence number */
           };
           GETVAL\SETVAL:设置参数2这一个信号灯中的值,放到参数4提供的整数中
           GETALL\SETALL:设置或获取所有信号灯的值,放入到参数4提供的数组中
        参数4:可变参数,会根据参数3的不同,使用的类型也不同,所以是一个共用体变量
        union semun {
               int              val;    /* 参数3为 SETVAL使用该成员 */
               struct semid_ds *buf;    /* 参数3位 IPC_STAT, IPC_SET使用该成员 */
               unsigned short  *array;  /* 参数3位 GETALL, SETALL 使用该成员*/
               struct seminfo  *__buf;  /* 参数3为 IPC_INFO
 使用该成员*/
           };
        返回值:对于GETVAL成功返回获取的信号号
                对于GETVAL:返回信号量集ID
                失败全部返回-1并置位错误码

 3、对信号灯进行PV操作(申请资源和释放资源)
        #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semop(int semid, struct sembuf *sops, size_t nsops);         
       功能:完成对信号灯集的相关操作
       参数1:信号灯集的id
       参数2:执行的操作,是一个结构体,成员如下
           unsigned short sem_num;  /* 要操作的信号灯的编号 */
           short          sem_op;   执行的操作:正数表示释放资源,负数表示申请资源
           short          sem_flg;  是否阻塞:0表示阻塞,IPC_NOWAIT表示非阻塞
        参数3:参数2的个数
        返回值:        成功返回0,失败返回-1并置位错误码              

二、 将信号量集函数再次封装

 1、sem.h

#ifndef SEM_H
#define SEM_H
#include <myhead.h>union semun
{int val;               /* 参数3为 SETVAL使用该成员 */struct semid_ds *buf;  /* 参数3位 IPC_STAT, IPC_SET使用该成员 */unsigned short *array; /* 参数3位 GETALL, SETALL 使用该成员*/struct seminfo *__buf; /* 参数3为 IPC_INFO
使用该成员*/
};// 创建信号灯集并初始化
// 返回值:信号灯集id
// 参数:信号灯集中灯的个数
int sem_create(int semcont);// 执行申请某个信号灯的资源操作(P操作)
// 返回值:成功返回0,失败返回-1
// 参数1:信号灯集id
// 参数2:要操作的信号灯编号
int P(int semid, int semnum);// 执行释放某个信号灯的资源操作(V操作)
// 返回值:成功返回0,失败返回-1
// 参数1:信号灯集id
// 参数2:要操作的信号灯编号
int V(int semid, int semnum);// 删除信号灯集
// 参数:信号灯id号
int sem_del(int semid);#endif

2、sem.c

#include"sem.h"
//定义设置某个信号灯的值的函数
int init_semnum(int semid, int semnum)
{int val = 0;printf("请输入第%d号灯的初始值:", semnum+1);scanf("%d", &val);getchar();//准备共用体变量union semun buf;buf.val = val;     //要传递的数据//调用semctl函数完成对信号灯的值的设置if(semctl(semid, semnum, SETVAL, buf)==-1){perror("semctl error");return -1;}return 0;
}//创建信号灯集并初始化
int sem_create(int semcont)
{//1、创建key值key_t key = ftok("/", 't');if(key == -1){perror("ftok error");return -1;}//2、创建信号量集int semid = semget(key, semcont, IPC_CREAT|IPC_EXCL|0664);if(semid == -1){//对错误码进行判断if(errno == EEXIST){//说明消息队列已经存在,直接打开即可semid = semget(key, semcont, IPC_CREAT|0664);return semid;}perror("semget error");return -1;}//3、对信号灯进行初始化for(int i=0; i<semcont; i++){init_semnum(semid, i);}//4、返回创建的信号灯集idreturn semid;}//P操作:申请资源
int P(int semid, int semnum)
{//定义操作结构体变量struct sembuf buf;buf.sem_num = semnum;   //要操作的信号灯buf.sem_op = -1;        //表示申请资源,如果semnum灯的资源为0,则阻塞buf.sem_flg = 0;          //表示如果没有资源,则阻塞//调用函数进行申请资源if(semop(semid, &buf, 1) ==-1){perror("P error");return -1;}//成功返回0return 0;
}//V操作:释放资源
int V(int semid, int semnum)
{//定义操作结构体变量struct sembuf buf;buf.sem_num = semnum;   //要操作的信号灯buf.sem_op = 1;        //表示申请资源,如果semnum灯的资源为0,则阻塞buf.sem_flg = 0;          //表示如果没有资源,则阻塞//调用函数进行申请资源if(semop(semid, &buf, 1) ==-1){perror("V error");return -1;}//成功返回0return 0;
}//删除信号灯集
int sem_del(int semid)
{//调用semctl删除信号灯集if(semctl(semid, 1, IPC_RMID) ==-1){perror("delete error");return -1;}printf("信号灯集删除成功\n");return 0;
}

三、使用信号量集完成共享内存的进程同步

 1、发送端

#include <myhead.h>
#include <sys/user.h>
#include "sem.h"int main(int argc, char const *argv[])
{//1、创建/打开信号量集int semid = sem_create(2);//2、创建key值用于创建共享内存段key_t key = ftok("/",'t');if (key == -1){perror("ftok error");return -1;}printf("key = %d\n",key);//3、创建一个共享内存的对象int shmid = shmget(key,PAGE_SIZE,IPC_CREAT|0664);if (shmid == -1){perror("shmget error");return -1;}printf("shmid = %d\n",shmid);//4、将共享内存段映射到程序中char *addr = (char *)shmat(shmid,NULL,0);printf("addr = %p\n",addr);//5、向共享内存中写入数据while(1){P(semid,0);printf("输入信息:");fgets(addr,PAGE_SIZE,stdin);addr[strlen(addr)-1] = 0;V(semid,1);if (strcmp(addr,"quit") == 0){printf("退出\n");break;}}//6、取消映射关系if (shmdt(addr) == -1){perror("shmdt error");return -1;}return 0;
}

2、接收端

#include <myhead.h>
#include <sys/user.h>int main(int argc, char const *argv[])
{// 1、创建key值用于创建共享内存段key_t key = ftok("/", 't');if (key == -1){perror("ftok error");return -1;}printf("key = %d\n", key);// 2、创建一个共享内存的对象int shmid = shmget(key, PAGE_SIZE, IPC_CREAT | 0664);if (shmid == -1){perror("shmget error");return -1;}printf("shmid = %d\n", shmid);// 3、将共享内存段映射到程序中char *addr = (char *)shmat(shmid, NULL, 0);printf("addr = %p\n", addr);//4、创建/打开信号量集int semid = sem_create(2);// 5、读出共享内存的数据while(1){P(semid,1);printf("接收到:%s\n",addr);if (strcmp(addr,"quit") == 0){break;}V(semid,0);}// 6、取消映射关系if (shmdt(addr) == -1){perror("shmdt error");return - 1;}// 7、删除共享内存if (shmctl(shmid, IPC_RMID, NULL) == -1){perror("shmctl error");return -1;}return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 未来展望:PLC远程控制网关与工业物联网融合的发展趋势
  • 【Linux】系列入门摘抄笔记-4-查看文件内容命令cat/more/less/tail
  • web基础与http协议与配置
  • 美的神机后续
  • 【Datawhale AI夏令营第四期】 Datawhale AI夏令营第四期 魔搭-AIGC方向 Task01笔记
  • Android 文件上传与下载
  • 引导过程与服务控制
  • springbootAl农作物病虫害预警系统-计算机毕业设计源码21875
  • 数据库|SQLServer数据库:数据的基本查询
  • 应急响应:D盾的简单使用.
  • MySQL 5.7 DDL 与 GH-OST 对比分析
  • TCP简易通信实现
  • 【图像超分】论文精读:SeD: Semantic-Aware Discriminator for Image Super-Resolution
  • Feapder 爬虫集群部署指南
  • STM32-USART时序与寄存器状态分析
  • 【Linux系统编程】快速查找errno错误码信息
  • 【个人向】《HTTP图解》阅后小结
  • 07.Android之多媒体问题
  • Elasticsearch 参考指南(升级前重新索引)
  • Java 23种设计模式 之单例模式 7种实现方式
  • Java多态
  • PHP面试之三:MySQL数据库
  • Vue--数据传输
  • 百度地图API标注+时间轴组件
  • 浮动相关
  • 解决iview多表头动态更改列元素发生的错误
  • 力扣(LeetCode)22
  • 排序(1):冒泡排序
  • 深度学习入门:10门免费线上课程推荐
  • 无服务器化是企业 IT 架构的未来吗?
  • 与 ConTeXt MkIV 官方文档的接驳
  • 阿里云ACE认证之理解CDN技术
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • $ git push -u origin master 推送到远程库出错
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (~_~)
  • (21)起落架/可伸缩相机支架
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (四)Controller接口控制器详解(三)
  • (一)SpringBoot3---尚硅谷总结
  • (一)基于IDEA的JAVA基础12
  • (一)模式识别——基于SVM的道路分割实验(附资源)
  • (一)项目实践-利用Appdesigner制作目标跟踪仿真软件
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)socket Aio demo
  • .Net Core中的内存缓存实现——Redis及MemoryCache(2个可选)方案的实现
  • 。。。。。
  • @kafkalistener消费不到消息_消息队列对战之RabbitMq 大战 kafka
  • @property @synthesize @dynamic 及相关属性作用探究
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决