IPC--信号量

Linux 专栏收录该内容
65 篇文章 0 订阅

信号量概念理解

  • 信号量本质上 是一个计数器,用来统计临界资源申请资源的个数。其中的二元信号量的 值是0或者是1,即是要么是有,要么是无。信号量本身也是临界资源,所以一定要保证其原子性。
  • 信号量的工作原理:两个进程共享一个信号量sv,一个进程访问的sv的时候,进行的是P操作即是减1操作,开始的时候信号量是1,它得到信号量进入临界资源。当他出来的时候进行v操作,使信号量加1。其他的进程访问的时候看见信号量是0,就不在访问了。
  • 现实形象比喻:比如我们的信号量是一个教室的,教室里面有很多座位,这就是临界资源。咱们设计是50,一开始同学想进教室的时候得去申请,比如现在门口站了一个人,它就是控制信号量的,第一个人进去的时候,使用P操作,将50减1,出来的时候加1,如果信号量是>0的 就可以进去,否则就不可以进去
  • 信号量 不以传送数据为目的,它是以协调使用临界资源进行 进程间通信为目的的,当我们申请信号量的时候,就可以得到信号量保护的临界资源。

信号量相关函数的使用

得到信号量(生成信号量)

int semget(key_t key,int nsem,int semflg)

参数解析
- key:这是一个key值,可以理解为一个端口,这个用函数ftok生成,一会介绍
- nsem:信号量的个数
- semflg:创建信号量的方式,它由两个固定标识位参数可以选择。如果是IPC_CREAT,表示如果有一个信号量则返回,如果没有则创建。IPC_EXCL,如果单独使用它没有任何的意义,但是如果和IPC_CREAT一起使用,就是IPC_CREAT|IPC_EXCL表示如果有信号量则出错返回,如果没有则创建,这样就可以保证我们每次使用的时候创建的是一个全新的信号量

返回值
如果失败返回-1,如果成功返回信号量标识符(信号量ID)

删除信号量

int semctl(int semid,int semnum,int cmd,...)

参数:
- semid:这个是删除的信号量的标识符(ID)
- semnum:这个是删除的信号量的个数,这里暂时设置0
- cmd:执行命令的方式,这里我们主要是为了删除一个信号量,可以直接使用IPC_RMID

初始化信号量

int semctl(int semid,int semnum,int cmd,...)
  • semid:这个是初始化信号量的标识符(ID)
  • semnum:这个是初始化信号量中的第几个信号量,数组下标的形式
  • cmd:执行命令的方式,这里我们是初始化信号量,传入的是特定的参数SETVAL,传入这个信号量的时候,需要传入第四个参数,这个参数应该是一个联合体,联合体的结构如下
union semnu{
  int val; // 使用的值
  struct semid_ds *buf; // IPC_STAT、IPC_SET 使用缓存区
  unsigned short *array; // GETALL,、SETALL 使用的数组
  struct seminfo *__buf; // IPC_INFO(Linux特有) 使用缓存区
};

我们在使用semctl进行 信号量初始化的时候,首先得先用上面的联合体定义一个对象,然后这个联合体是需要我们自己定义的,然后把实例化的这个对象的val设置为1(这里我们使用的是二元信号量)

函数使用示例:
union semnu _semnu;
semctl(semid,semnum,SETVAL,_semnu);

返回值:失败返回-1

信号量Pv操作

int semop(int semid,struct sembuf* sops,unsigned nsops)

参数
- semid:信号量标识符
- sops:这个也是需要我们提前实例化一个对象,这里我们可以传递的是一个结构体数组,也可以是一个结构体的地址
- nspos:是结构体的个数,因为上一个参数是一个数组

这里第二个参数也是一个结构体,这个结构体是系统自定义的结构体,不需要我们定义,我们可以直接调用它,这里结构体的内容 如下

struct sembuf{
    unsigned short sem_num;
    short sem_op;
    short sem_flag;
};

num:标记信号量集中的第几个
sem_op:标记是那种操作,比如二元信号量p设置为-1,如果是v操作设置为1
sem_flag:我们此时默认设置为0

讨论信号量的几种情况

  • 当我们的某一个进程已经进行 p操作,拿到信号量维护的共享资源之后,这个时候可以有一种可能该进程被其他进程替换掉了,但是这个时候信号量依然被该进程拿着,等它下一次切换进来的时候还可以继续原来的操作
  • 另外的一种情况是,某一进程拿到信号量之后,因为某些原因被杀死,这个时候信号量还在改进程里面,其他的进程就无法获得该信号量,这个情况就是问题所在。这个时候我们可以设置信号量的的结构体,就是上面的结构体sem_flag,可以把它设置为SEM_UNDO,这个时候进程退出的时候,它所拿到的信号量就会释放掉,比如二元信号量原来是0,如果使用这个选项后,当进程退出后就会变成是1。

补充两个linux的指令:
- ipcs -s :查看当前信号量
- ipcrm -s 信号量标识符:删除某一个信号量
- ipcs -q:查看当前消息队列数
- ipcrm -q 消息队列标识符:删除某一个消息队列

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

NeilZhy

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值