进程间通信——信号量

信号量
信号量的作用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。
信号量的值为正的时候,说明它空闲。测试的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。

为什么要使用信号量?
因为共享内存是可以由多个进程同时访问,假如有多个进程同时访问同一块地址的话,内存就会出错,或者是 运算错误,所以当某个进程访问共享内存的时候,我们利用信号量去保护这片共享内存以防内存出错。

信号量的分类
在学习信号量之前,我们必须先知道—— Linux 提供两种信号量:
(1) 内核信号量,由内核控制路径使用
(2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量SYSTEM V信号量 POSIX信号量又分为有名信号量无名信号量
               有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步。
               无名 信号量,其值保存在内存中。

信号量的使用步骤
1.创建信号量---》 semget
2.初始化信号量---》 semctl
3.进行信号量的操作---》 semop



1.创建信号量
头文件:
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
函数原型:
    int semget(key_t key, int nsems, int semflg);
参数一:秘钥ftok()
参数二:需要创建信号量的个数 PS:(信号量是有个数的他从0下标开始)
参数三:权限
IPC_CREAT  -》创建
IPC_EXCL   -》检查
|0666       -》操作权限
返回值:信号量对象ID
失败返回:-1 

2.初始化信号量
int semctl(int semid, int semnum, int cmd, ...);
参数一:要初始化的信号量对象ID
参数二:要初始化那个信号量
参数三:命令  GETVAL -》获取当前信号量的值(一般设备完毕后需要获取一下值 ,该值会放到返回值中)
     SETVAL  -》设置信号量的值   (该值应该填写到第4个参数中)
     IPC_RMID -》删除信号量对象
参数四:通过命令来确定他的值
   union semun {
               int              val;    /* Value for SETVAL */ //设置一个信号量的值
               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) */
};

3.进行信号量的P\V操作 
p -> 申请资源            V -> 释放资源
头文件:
            #include <sys/types.h>
           #include <sys/ipc.h>
         #include <sys/sem.h>
函数原型:
    int semop(int semid, struct sembuf *sops, unsigned nsops);
参数一:对象ID
参数二:操作结构体
 struct sembuf
 {
   unsigned short sem_num;  /* semaphore number */要操作哪一个信号量
           short          sem_op;   /* semaphore operation */PV操作 
P操作 填写 -1
          V操作 填写  1
           short          sem_flg;  /* operation flags */
                    IPC_NOWAIT  不阻塞
SEM_UNDO  -》自动释放资源
0       -》默认操作
 }
参数三:整形  -》 指定参照二的结构体数量  一般填写为1 

-----------------------------------------------------------------------------------------
练习:使用信号量的pv操作
【sema.c】
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
   //创建信号量对象
	 int semid=semget(ftok("/home/gec",400),2,IPC_CREAT|0666);
		if(semid == -1)
		{
			perror("semid fail:");
			 exit(0);
		}
		else
		{
		  printf("crete ok\n");
		}
    
		//对信号量1进行初始化
		int ret=semctl(semid,0,SETVAL,1);
		if(ret == -1 )
		{
		  perror(" init sem:");
		  exit(0);
		}
		else
		{
		printf("init 1 ok %d\n",semctl(semid,0,GETVAL,NULL));	
		}
		//对信号量2进行初始化
     	 ret=semctl(semid,1,SETVAL,1);
		if(ret == -1 )
		{
		  perror(" init sem:");
		   exit(0);
		}
		else
		{
		printf("init 2 ok %d\n",semctl(semid,0,GETVAL,NULL));	
		}	
	//进行P-1   V+1操作
	 struct sembuf  p;
	 p.sem_num = 0;   //要操作哪一个信号量
	 p.sem_op = -1;   // -1为P操作   1为V操作
	 p.sem_flg =  0;  //默认属性
	 
	 struct sembuf  v; 
	 v.sem_num = 0;
	 v.sem_op = 1;
	 v.sem_flg = 0;
	 
	 //进行PV操作2
     struct sembuf  p1;
	 p1.sem_num = 1;   //要操作哪一个信号量
	 p1.sem_op = -1;   // -1为P操作   1为V操作
	 p1.sem_flg =  0;  //默认属性
	 
	 struct sembuf  v1; 
	 v1.sem_num = 1;
	 v1.sem_op = 1;
	 v1.sem_flg = 0;

	int i=0;
	 while(1)
	 {
	  //进行P操作
	  semop(semid,&p,1);
	  printf("i=%d\n",i++);
	  sleep(1);
	  //进行V操作
	  semop(semid,&v1,1);		
	}
}


【semb.c】
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
   //创建信号量对象
	 int semid=semget(ftok("/home/gec",400),2,IPC_CREAT|0666);
		if(semid == -1)
		{
			perror("semid fail:");
			exit(0);
		}
		else
		{
		  printf("crete ok\n");
		}
	
	//进行P-1   V+1操作
	 struct sembuf  p;
	 p.sem_num = 0;   //要操作哪一个信号量
	 p.sem_op = -1;   // -1为P操作   1为V操作
	 p.sem_flg =  0;  //默认属性
	 
	struct sembuf  v; 
	v.sem_num = 0;
	v.sem_op = 1;
	v.sem_flg = 0;

	 //进行PV操作2
     struct sembuf  p1;
	 p1.sem_num = 1;   //要操作哪一个信号量
	 p1.sem_op = -1;   // -1为P操作   1为V操作
	 p1.sem_flg =  0;  //默认属性
	 
	 struct sembuf  v1; 
	 v1.sem_num = 1;
	 v1.sem_op = 1;
	 v1.sem_flg = 0;
	 
	 int i=0;
	 while(1)
	 {
	  //进行P操作
	  semop(semid,&p1,1);
	  printf("i=%d\n",i++);
	  sleep(1);
	  //进行V操作
	  semop(semid,&v,1);	
	}
}



运行程序sema.c,初始化信号量1,2,运行semb.c后,两个进程的变量i每隔1s加1.
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值