IPC学习笔记:systemV信号灯集+共享内存

一、信号量集函数

1.1、semget

  • 功能:用来创建或打开一个信号量集;

  • 原型:int semget(key_t key, int nsems, int semflg);

  • key表示信号集的名字,一般由ftok函数产生;

  • nsems 表示信号集中信号量的个数;

  • semflg 用来标识信号量集合的权限,和创建文件类似,由九个权限标志为构成如0644,他还可以和以下参数一起使用:

    IPC_CREAT 表示如果key不存在就创建;
    
    IPC_EXCL 表示如果key存在就返回失败;
    
    IPC_NOWAIT 表示如果需要等待,则直接返回错误;
    
  • 返回值:成功返回一个非负整数即该信号量的标识码;失败返回-1;

1.2、semctl

  • 功能:用来控制信号量集;

  • 原型:int semctl(int semid, int semnum, int cmd, …);

  • semid由semget返回的信号量标识;

  • semnum指定信号集中信号量的序号;

  • cmd表示将要采取的操作;cmd可采取的操作有:IPC_RMID、IPC_SET、IPC_STAT和IPC_INFO,定义在:/usr/include/linux/ipc.h中;

      ——IPC_RMID表示删除信号集
      
      ——IPC_STAT表示获取ipc_perm的参数
      
      ——IPC_INFO表示获取系统信息
      
      ——IPC_SET表示设置ipc_prem的参数,对于这个参数,semctl有单独的规定参数:
      
      		——GETPID获取信号量拥有者的pid的值;
      		
      		——GETVAL获取信号量的值;
      		
      		——GETALL获取所有信号量的值;
      		
      		——GETNCNT获取等待信号量的值递增的进程数;
      		
      		——GETZCNT获取等待信号量的值递减的进程数;
      		
      		——SETVAL设置信号量的值;
      		
      		——SETALL设置所有信号的值;
    
  • 最后一个参数根据命令不同而不同,他是一个类型为senum的联合体,不操作结构体则为0

    union semun{
    	int value;
    	struct semid_ds *buf;
    	unsigned short *array;
    	struct seminfo *_buf;
    }
    
  • 返回值 成功返回0,失败返回-1

1.3、semop

  • 功能:修改集合中一个或多个信号量值;
  • 原型:int semop(int semid, struct sembuf *sops, unsigned nsops);
  • semid信号量标识码;
  • nsops标识信号量个数;
  • 返回值:成功返回0;失败返回-1;
  • sops是一个sembuf类型的指针;
struct sembuf{
	short sem_num;//信号量名称
	short sem_op;//计数值操作-1,1
	short sem_flg;//选项,默认为0,表示计数值小于减去的数,便会阻塞
}
——sem_num标识信号量编号;

——sem_op信号量一次pv操作时加减的数值,一般会用到两个值:

	-1,p操作,等待信号量变得可用
	
	+1,v操作,发出的信号量变得可用

——sem_flg操作标识,有以下值: IPC_NOWAIT和SEM_UNDO

	IPC_NOWAIT对某一信号量操作,即使其中一个操作失败,也不会导致修改其他信号量的值;
	
	SEM_UNDO当进程退出后,该进程对sem进行的操作将被撤销;

二、两进程读写同步练习

 /* 信号灯集+共享内存*/
 /* 
 要求:父子进程通过SystemV信号灯集同步对共享内存的读写 
  1.父进程从键盘输入字符串到共享内存
  2.子进程删除字符串中的空格并打印
  3.父进程输入quit后删除共享内存和信号灯集,程序结束
 思路:
实现内存(缓冲区)读写同步机制+互斥机制,需要2个信号灯,一个为读,一个为写。
 1.创建共享内存                                                              
 2.创建信号灯
 3.fork进程
 4.父进程阻塞等待键盘输入
 4..阻塞等待P写资源
 4...写入共享内存
 4....判断是否结束,如果是则kill子进程
 4.....如果否,则V读资源
 5.子进程阻塞等待P读资源
 5..读取共享内存
 5...V写资源
 5....打印输出
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <wait.h>
#include <string.h>
#define SEM_WRITE		0		//写信号灯编号
#define	SEM_READ		1
#define	P_OPERATION		-1		//systemV-P操作
#define V_OPERATION		1		//V操作
typedef	union semunion{
		int val;
		struct semid_ds *buf;
		unsigned short *array;
		struct seminfo *__buf;
	}semunion;

/*
func:对num个信号灯赋值
para:
	semid 信号灯集id
	sema_value[] 信号灯值缓冲区
	num 信号灯个数

*/
void init_sema_value(int semid,int *sema_value,int num){

	semunion semu;
	for(int i=0;i<num;i++){
		semu.val=sema_value[i];
		semctl(semid,i,SETVAL,semu);
	}
}
/*
func:P/V操作封装
para:
 */
void operate(int semid,int whichnum,int op){
	struct sembuf opbuf;
	opbuf.sem_num=whichnum;
	opbuf.sem_op=op;
	opbuf.sem_flg=0;
	semop(semid,&opbuf,1);
}
int main(void)
{
	int shmid,semid,sema_value[2];
	pid_t pid;
	char *addr=NULL;
	key_t Key;
	Key=ftok(".",'m');
	//创建共享内存
	if((shmid=shmget(Key,1024,IPC_CREAT|0666))<0){
		perror("shmget");
		exit(-1);
	}
	//创建信号灯集
	if((semid=semget(Key,2,IPC_CREAT|0666|IPC_EXCL))<0){
		perror("semget");
		goto error1;
	}
	//信号灯初始化
	sema_value[SEM_WRITE]=1;
	sema_value[SEM_READ]=0;
	init_sema_value(semid,sema_value,2);
	//映射共享内存
	if((addr=(char *)shmat(shmid,NULL,0))<0){
		perror("shmat");
		goto error2;
	}
	if((pid=fork())==0){
		char *new,*old;
		while(1)		//子进程循环
		{
			operate(semid,SEM_READ,P_OPERATION);	//对读信号灯的P操作
			new=old=addr;
			while(*old){
				if((*old)!=' '){
					(*new++)=(*old);
				}
				old++;
			}
			(*new)='\0';
			//if(strcmp(addr,"quit\n")==0)exit(0);
			printf("your input is : %s\n",addr);
			operate(semid,SEM_WRITE,V_OPERATION);	//对写信号灯的V操作
		}
	}
	else
	{
		while(1)		//父进程
		{
			operate(semid,SEM_WRITE,P_OPERATION);
			printf("please input something:\n");
			fgets(addr,1024,stdin);
			if(strcmp(addr,"quit\n")==0)
			{
				kill(pid,SIGUSR1);
				//waitpid(pid,NULL,0);
				break;
			}
			operate(semid,SEM_READ,V_OPERATION);
		}
	}
	
error2:
	semctl(semid,0,IPC_RMID);		//删除信号灯集
	shmdt(addr);					//撤销共享内存映射
error1:
	shmctl(shmid,IPC_RMID,NULL);	//删除共享内存

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值