进程间通信【信号量】

信号量描述

信号量就是控制某个进程能够对某个资源进行访问;保证某一时刻只能由一个进程对某个资源进程访问

  • 信号量是一个特殊的变量,一般去正值。它的值代表允许访问的资源数目
  • 获取资源时,需要对信号量的值进行原子减一,该操作成为P操作。当信号量值为0时,代表没有资源可用,P操作阻塞;释放资源时,需要对信号量的值进行原子加一,该操作被称为V操作
  • 信号量主要用于同步进程,如果信号量的值只取0、1,将其成为二值信号量。如果信号量的值大于一,则称之为计数信号量

临界资源和临界区

临界资源:同一时刻,只允许被一个进程或者线程访问的资源
临界区:访问临界资源的代码段

“不加控制模拟使用打印机”示例

描述:进程a,b模拟访问打印机,a输出第一个字符A表示开始使用打印机,输出第二个A表示结束使用,b进程操作与a相同。(由于打印机同一时刻只能被一个进程使用,所以输出结果不可能出现ABAB这样交替出现的结果)

a.c

在这里插入图片描述

b.c

在这里插入图片描述
同时访问打印机指令:./a& ./b&(使a,b进程同时在后台运行)
运行结果:
在这里插入图片描述

信号量使用

信号量接口介绍

头文件

#include<sys/sem.h>
#include<sys/types.h>
#include<sys/ipc.h>
int semget(key_t key,int nsems,int semflg);

**semget()创建或者获取已存在的信号量;
**semget()成功返回信号量的ID,失败返回-1**key:两个进程使用相同的key值,就可以使用同一个信号量;
**nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号量的个数;
**semflg:IPC_CREAT IPC_EXCL
int semop(int semid,struct sembuf*sops,unsigned nsops);

**semop()对信号量进行改变,进行PV操作
**semop()成功返回0,失败返回-1**semid:信号量的id号,即semget的返回值,说明对哪个信号量尽心操作;
**sops:结构体指针,指向sembuf的结构体指针
**
struct sembuf
{
	unsigned short sem_num;//指定信号量集中的信号量下标(信号量编号)
	short sem_ops;//其值为-1,代表P操作;其值为1,代表V操作
	short sem_flg;//SEM_UNDO标志位
};
int semctl(int semid,int semnum,int cmd,...);

**semctl()控制信号量,能够对信号量进行初始化和删除操作
**semid:信号量id
**semnum:信号量编号
cmd命令:
SETVAL:初始化信号量;
IPC_RMID:删除信号量;
*******************
**联合体semun
union semun
{
	int   val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo *_buf;
}
seminit()//初始化包含创建+初始化:semget()-semctl()
sem_p()//控制信号量:semop()-1
sem_v()//semop()+1
sem_destory()//删除操作semctl()

借用信号量对上述打印机出错的情况进行修正

在这里插入图片描述

1、封装信号量的接口

sem.h
存放头文件以及函数声明

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/sem.h>
//定义联合体
union emun
{
	int val;
};
void sem_init();
void sem_p();
void sem_v();
void sem_disrory();

sem.c

#include "sem.h"
static int semid=-1;
//信号量的初始化需要进行创建+初始化操作
void sem_init()
{
	semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
	if(semid=-1)
	{
		//创建失败,可能是信号量已经创建,则重新获取即可,0600属于补位
 		semid=semget((key_t)1234,1,0600);
 		if(semid==-1)
 		{
 			//持续失败,则无法创建
 			printf("creat semid failed\n");
 		}
	}
	else//创建成功,开始初始化
	{
		union semun a;//定义联合体a
		a.val=1;
		if(semctl(semid,0,SETVAL,a)==-1)
		{
			printf("semctl init failed\n");
		}
	}
}
void sem_p()
{
	//由于只创建一个信号量,则只申请一个结构体,传入地址即可
	struct sembuf a;
	a.sem_num=0;//只有一个信号量,下标为0
	a.sem_op=-1;//P操作
	//防止获取资源进行P操作之后,进程的异常终止
	//标志位可以将原来对信号量所做的操作,反过来再做一遍,即原来属于P操作,标志位将再做一遍V操作
	a.sem_flg=SEM_UNDO;

	if(smeop(semid,&a,1)==-1)
	{
		printf("sem_p failed\n");
	}
}
void sem_v()
{
	//由于只创建一个信号量,则只申请一个结构体,传入地址即可
	struct sembuf a;
	a.sem_num=0;//只有一个信号量,下标为0
	a.sem_op=-1;//P操作
	//防止获取资源进行P操作之后,进程的异常终止
	//标志位可以将原来对信号量所做的操作,反过来再做一遍,即原来属于P操作,标志位将再做一遍V操作
	a.sem_flg=SEM_UNDO;

	if(smeop(semid,&a,1)==-1)
	{
		printf("sem_v failed\n");
	}
}
void sem_distory()
{
	if(semctl(semid,0,IPC_RMID)==-1)
	{
		//删除给定信号量的ID即可删除一组信号量
		printf("sem_distory failed\n");
	}
}

2、程序修改

d.c

在这里插入图片描述

e.c

在这里插入图片描述
运行截图
在这里插入图片描述

ipcs/ipcrm介绍

  • ipcs可以查看消息队列、共享内存、信号量的使用情况
  • ipcrm能够进行信号量删除

在这里插入图片描述
在这里插入图片描述
思考:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值