进程间通信之---信号量浅谈以及小例子

           众所周知,进程间通信有三种方式,信号量、消息队列和共享内存。不过信号量个人感觉不像通信,其实就是一个锁的东西。

                 这部分内容分几个部分

                1.API

                 创建信号量   int semget(key_t key,int nsems,int semflg);  返回值就是信号量标识semid  

key:所创建或打开信号量集的键值。
nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。
flag:调用函数的操作类型,也可用于设置信号量集的访问权限,两者通过or表示
    操作信号量   int semctl(int semid,int semnum,int cmd, /*union semun arg*/);  cmd表示操作类型,具体自己查资料吧,内容太大了;
   PV 操作通过调用semop函数来实现:int semop(int semid,struct sembuf *sops,size_t nsops);
             这里涉及到两个内核的数据结构,一个是union semun ,另一个是sembuf
    先说sembuf,是一个结构体,要熟记,结构如下:
struct sembuf{
unsigned short sem_num;
short sem_op;
short sem_flg;
} 在sembuf结构中,sem_num是相对应的 信号量集 中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。sem_op指明所要执行的操作,sem_flg说明 函数 semop的行为。sem_op的值是一个整数,如表2所示,列出了详细sem_op的值及所对应的操作。
sem_op值详解(关键)
Sem_op
操 作
正数
释放相应的资源数,将sem_op的值加到信号量的值上
0
进程阻塞直到信号量的相应值为0,当信号量已经为0,函数立即返回。如果信号量的值不为0,则依据sem_flg的IPC_NOWAIT位决定函数动作。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生。信号量值为0,将信号量的semzcnt的值减1,函数semop成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM;进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR
负数
请求sem_op的绝对值的资源。如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。当相应的资源数不能满足请求时,这个操作与sem_flg有关。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。sem_flg没有指定IPC_NOWAIT,则将该信号量的semncnt值加1,然后进程挂起直到下述情况发生:当相应的资源数可以满足请求,该信号的值减去sem_op的绝对值。成功返回;此信号量被删除(只有超级用户或创建用户进程拥有此权限),函数smeop出错返回EIDRM:进程捕捉到信号,并从信号处理函数返回,在此情况将此信号量的semncnt值减1,函数semop出错返回EINTR
然后再说semun:
union semun
{
     int val;
     struct semid_ds *buf;
     unsigned short int *array;
     struct seminfo *__buf;
};      这里面要用到的变量是val

2 直接上小例子吧,这样容易理解:producer.c 建立一个信号量 每隔3秒对val值不停减1;customer.c 读取val值,直到val=0
producer.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
union semun//由于类型是union 需要在这里初始化一下
{
     int val;
     struct semid_ds *buf;
     unsigned short int *array;
     struct seminfo *__buf;
};
int main(int argc, char const *argv[])
{
	int semid;
	key_t key;
	key=ftok(".",3);  //ftok的作用就是计算一个key值供使用,一般用当前目录文件结点索引号来计算,如指定文件的索引节点号为65538,换算成16进制为0x10002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x2610002。
	semid=semget(key,1,IPC_CREAT|0666);//创建并得到信号量id
	if(semid==-1){
		perror("semget");
		exit(1);
	}
	printf("my semid is %d \n",semid);
	struct sembuf sbuf={0,-1,IPC_NOWAIT};// 上面sembuf结构体介绍中说,当sem_op=负数,请求sem_op的绝对值的资源。如果相应的资源数可以满足请求,则将该信号量的值减去sem_op的绝对值,函数成功返回。当相应的资源数不能满足请求时,这个操作与sem_flg有关。sem_flg指定IPC_NOWAIT,则semop函数出错返回EAGAIN。
	union semun semopts; 
	semopts.val=5;  //对val赋值
	if((semctl(semid,0,SETVAL,semopts))==-1){  // SETVAL就是给semun.val赋值的动作
		perror("semctl");
		exit(1);
	}
	printf("%s\n","ke" );
	while(1){
		if(semop(semid,&sbuf,1)==-1)  // 这个操作就是semop来对{0,-1,IPC_NOWAIT}对应的动作  不断-1,直到=0
			exit(1);
		sleep(3);
	}
	return 0;
}
customer.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
int main(int argc, char const *argv[])
{
	int semid,semval;
	key_t key;
	key=ftok(".",3);  //必须仍然用这两个值计算,不然信号量对应不起来,当然前提是两个代码位于相同的路径下
	semid=semget(key,1,IPC_CREAT|0666); 
	if(semid==-1){
		perror("semget");
		exit(1);
	}
	int val;
	while(1){
		if((semval=semctl(semid,0,GETVAL,0))==-1)//GETVAL得到semun.val值
			exit(1);
		if(semval>0)
			printf("val is %d\n",semval);
		else{
			printf("stop!\n");
			break;
		}
		sleep(3);
	}
	return 0;
}
结果:
val is 4
val is 3
val is 2
val is 1
stop!
 两个进程确实通信成功。







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值