Linux --共享内存单向读写举例(非同步->同步机制)

用到的函数: Liunux – ftok函数

  1. 部分内核的宏:
    #ifndef _ASM_GENERIC_ERRNO_BASE_H
    #define _ASM_GENERIC_ERRNO_BASE_H
    
    #define EPERM        1  /* Operation not permitted */
    #define ENOENT       2  /* No such file or directory */
    #define ESRCH        3  /* No such process */
    #define EINTR        4  /* Interrupted system call */
    #define EIO      5  /* I/O error */
    #define ENXIO        6  /* No such device or address */
    #define E2BIG        7  /* Argument list too long */
    #define ENOEXEC      8  /* Exec format error */
    #define EBADF        9  /* Bad file number */
    #define ECHILD      10  /* No child processes */
    #define EAGAIN      11  /* Try again */
    #define ENOMEM      12  /* Out of memory */
    #define EACCES      13  /* Permission denied */
    #define EFAULT      14  /* Bad address */
    #define ENOTBLK     15  /* Block device required */
    #define EBUSY       16  /* Device or resource busy */
    #define EEXIST      17  /* File exists */
    #define EXDEV       18  /* Cross-device link */
    #define ENODEV      19  /* No such device */
    #define ENOTDIR     20  /* Not a directory */
    #define EISDIR      21  /* Is a directory */
    #define EINVAL      22  /* Invalid argument */
    #define ENFILE      23  /* File table overflow */
    #define EMFILE      24  /* Too many open files */
    #define ENOTTY      25  /* Not a typewriter */
    #define ETXTBSY     26  /* Text file busy */
    #define EFBIG       27  /* File too large */
    #define ENOSPC      28  /* No space left on device */
    #define ESPIPE      29  /* Illegal seek */
    #define EROFS       30  /* Read-only file system */
    #define EMLINK      31  /* Too many links */
    #define EPIPE       32  /* Broken pipe */
    #define EDOM        33  /* Math argument out of domain of func */
    #define ERANGE      34  /* Math result not representable */
    
    #endif
    
  2. 非同步机制
    shm_write.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <asm-generic/errno-base.h>
    #include <unistd.h>
    #include <strings.h>
    #include <string.h>
    
    #define handle_error(msg) \
    	do { perror(msg); exit(EXIT_FAILURE); } while (0)
    	       
    struct use_buf
    {
        int flag;
        /*由于这里没有使用信号量实现互斥操作,所以使用一个标志(1:表示可读,0:表示可写)来互斥操作同一块内存区*/
    	char buf[100]; // 数据
    };
    
    int 
    main(void){
    	
    	int shmid;
    	key_t ret_fk;
    	struct use_buf *shm_buf=NULL; 
    	if((ret_fk=ftok("/", 'a'))==-1){
    		handle_error("ftok");
    	}
    	/*判断键值对应的共享内存是否存在,不存在创建共享内存*/
    	if((shmid=shmget(ret_fk, sizeof(struct use_buf), IPC_CREAT|IPC_EXCL|0600))==-1){ 
    		if(EEXIST==errno){ /*如果键值对应的共享内存已存在*/			
    			shmid=shmget(ret_fk, sizeof(struct use_buf), 0); /*获取共享内存标识*/
    			printf("键值(%#x)对应的共享内存(%d)已存在\n",ret_fk,shmid);
    		}
    		else
    			handle_error("shmget");
    	}else
    		fprintf(stdout, "键值(%#x)创建共享内存成功,共享内存编号为%d\n",ret_fk,shmid);	
    	
    	if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){
    		shmctl(shmid, IPC_RMID, NULL);
    		handle_error("shmat");     /*共享内存映射,系统自动分配地址、共享内存可读写*/
    	}
    	shm_buf->flag = 0; /*初始化标志*/
    	
    	while(1){
    		
    		if(1==shm_buf->flag){ /*数据未读走*/
    		//	printf("Waiting...\n");
    		//	sleep(1);
    		}else{
    			bzero(shm_buf->buf, sizeof(shm_buf->buf));
    			printf("请输入数据:");
    			fgets(shm_buf->buf,sizeof(shm_buf->buf)-1,stdin);
    			shm_buf->flag=1; /*数据写入完成,标志变成可读*/
    			
    			if(!strncasecmp(shm_buf->buf, "quit", strlen("quit")))
    				break;
    		}
    		
    	}
    	
    	if(-1==shmdt((struct use_buf *)shm_buf)){
    		handle_error("shndt"); /*解除当前进程与共享内存的映射*/
    	}
    	
    	if(-1==shmctl(shmid, IPC_RMID, NULL)){
    		handle_error("shnctl"); /*删除共享内存*/
    	}
    	return 0;
    }
    
    shm_read.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <asm-generic/errno-base.h>
    #include <unistd.h>
    #include <strings.h>
    #include <string.h>
    
    #define handle_error(msg) \
    	do { perror(msg); exit(EXIT_FAILURE); } while (0)
    	       
    struct use_buf
    {
        int flag; //由于这里没有使用同步机制,使用一个标志,1:表示可读,0:表示可写*/
    	char buf[100]; // 数据
    };
    
    int 
    main(void){
    	
    	int shmid;
    	key_t ret_fk;
    	struct use_buf *shm_buf=NULL; 
    	if((ret_fk=ftok("/", 'a'))==-1){
    		handle_error("ftok");
    	}
    	/*判断键值对应的共享内存是否存在,不存在创建共享内存*/
    	if((shmid=shmget(ret_fk, sizeof(struct use_buf), IPC_CREAT|IPC_EXCL|0600))==-1){ 
    		if(EEXIST==errno){ /*如果键值对应的共享内存已存在*/			
    			shmid=shmget(ret_fk, sizeof(struct use_buf), 0); /*获取共享内存标识*/
    			printf("键值(%#x)对应的共享内存(%d)已存在\n",ret_fk,shmid);
    		}
    		else
    			handle_error("shmget");
    	}else
    		fprintf(stdout, "键值(%#x)创建共享内存成功,共享内存编号为%d\n",ret_fk,shmid);	
    	
    	if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){
    		handle_error("shmat");     /*共享内存映射,系统自动分配地址、共享内存可读写*/
    	}
    
    	while(1){
    		
    		if(0==shm_buf->flag){ /*未写数据*/
    		//	printf("Waiting...\n");
    		//	sleep(1);
    		}else{
    			printf("读出数据:");
    			fputs(shm_buf->buf,stdout);
    			shm_buf->flag=0; /*数据写出完成,标志变成可写*/
    			
    			if(!strncasecmp(shm_buf->buf, "quit", strlen("quit")))
    				break;
    		}
    		
    	}
    	if(-1==shmdt((struct use_buf *)shm_buf)){
    		handle_error("shndt"); /*解除当前进程与共享内存的映射*/
    	}	
    	
    	return 0;
    }
    
    缺点: 由于没有采用同步机制,shm_read进程一直在循环,这种方式会将cpu资源耗完
      
  3. 同步机制
    shm_write.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <asm-generic/errno-base.h>
    #include <unistd.h>
    #include <strings.h>
    #include <string.h>
    #include "sem.h"
    #include <signal.h>
    
    #define handle_error(msg) \
    	do { perror(msg); exit(EXIT_FAILURE); } while (0)
    	       
    struct use_buf
    {
        int flag; //不使用该标志,使用信号量互斥操作
    	char buf[100]; // 数据
    };
    
    int shmid;
    int semid;
    struct use_buf *shm_buf=NULL; 
    
    
    void user_quit_handle(int signo){
    	
    	if(SIGINT==signo){		
    	
    		system("killall INT shm_read"); /*关闭共享内存读进程*/
    		
    		if(-1==shmdt((struct use_buf *)shm_buf)){
    			handle_error("shndt"); /*解除当前进程与共享内存的映射*/
    		}
    		
    		if(-1==shmctl(shmid, IPC_RMID, NULL)){
    			handle_error("shnctl"); /*删除共享内存*/
    		}
    		if(-1==del_sem(semid)){
    			handle_error("del_sem"); /*删除信号量集*/
    		}
    		exit(EXIT_SUCCESS);
    	}
    	
    }
    
    int 
    main(void){
    	
    	char tmp_buf[100];
    
    	/*判断键值对应的共享内存是否存在,不存在创建共享内存,存在返回共享内存标识符*/
    	if((shmid=shmget(ftok("/", 'a'), sizeof(struct use_buf), IPC_CREAT|0600))==-1){ 
    		handle_error("shmget");
    	}
    	/*判断键值对应的信号量是否存在,不存在创建信号量,存在返回信号量标识符*/
    	if((semid=get_sem(ftok("/", 1), 2))== -1){ /*创建信号量集(两个信号量)对共享内存进行互斥同步操作*/
    		exit(EXIT_FAILURE);
    	}
    		
    	if(-1==set_sem_val(semid, 0, 1)){//初始化为共享内存起始状态可写
    		exit(EXIT_FAILURE);
    	}
    	
    	if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){
    		handle_error("shmat");     /*共享内存映射,系统自动分配地址、共享内存可读写*/
    	}
    	if(SIG_ERR==signal(SIGINT, user_quit_handle)){ /*注册SIGINT信号处理函数*/
    		handle_error("signal"); 
    	}
    	bzero(shm_buf->buf, sizeof(shm_buf->buf)); /*清空共享内存buf部分*/
    	while(1){
    		
    		printf("请输入数据:");	
    		bzero(tmp_buf, sizeof(tmp_buf));		
    		if(NULL==fgets(tmp_buf,sizeof(tmp_buf)-1,stdin)){
    			perror("fgets");
    		}					
    		sem_P(semid, 0); /*写P操作*/		
    		strncpy(shm_buf->buf, tmp_buf, strlen(tmp_buf));							
    		if(!strncasecmp(tmp_buf, "quit", strlen("quit"))){			
    			sem_V(semid, 1); /*读V操作*/
    			break;
    		}
    		sem_V(semid, 1); /*读V操作*/
    	}
    
    	
    	if(-1==shmdt((struct use_buf *)shm_buf)){
    		handle_error("shndt"); /*解除当前进程与共享内存的映射*/
    	}
    	
    	if(-1==shmctl(shmid, IPC_RMID, NULL)){
    		handle_error("shnctl"); /*删除共享内存*/
    	}
    	if(-1==del_sem(semid)){
    		handle_error("del_sem"); /*删除信号量集*/
    	}
    	return 0;
    }
    
    shm_read.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <asm-generic/errno-base.h>
    #include <unistd.h>
    #include <strings.h>
    #include <string.h>
    #include "sem.h"
    
    #define handle_error(msg) \
    	do { perror(msg); exit(EXIT_FAILURE); } while (0)
    	       
    struct use_buf
    {
        int flag; //不使用该标志,使用信号量互斥操作
    	char buf[100]; // 数据
    };
    
    int 
    main(void){
    	
    	int shmid;
    	int semid;
    	struct use_buf *shm_buf=NULL; 
    
    	/*判断键值对应的共享内存是否存在,不存在创建共享内存,存在返回共享内存标识符*/
    	if((shmid=shmget(ftok("/", 'a'), sizeof(struct use_buf), IPC_CREAT|0600))==-1){ 
    		handle_error("shmget");
    	}
    	/*判断键值对应的信号量是否存在,不存在创建信号量,存在返回信号量标识符*/
    	if((semid=get_sem(ftok("/", 1), 2))== -1){ /*创建信号量集(两个信号量)对共享内存进行互斥同步操作*/
    		exit(EXIT_FAILURE);
    	}
    	
    	if((shm_buf=(struct use_buf *)shmat(shmid, 0, 0))==(void *)-1){
    		handle_error("shmat");     /*共享内存映射,系统自动分配地址、共享内存可读写*/
    	}
    
    	while(1){
    		
    		
    		sem_P(semid, 1); /*读P操作*/	
    		printf("读出数据:%s",shm_buf->buf);
    		bzero(shm_buf->buf, sizeof(shm_buf->buf));	
    									/*读出数据后清空共享内存buf部分*/
    		if(!strncasecmp(shm_buf->buf, "quit", strlen("quit"))){	 				
    			sem_V(semid, 0); /*写V操作*/
    			break;
    		}
    		bzero(shm_buf->buf, sizeof(shm_buf->buf));
    		sem_V(semid, 0); /*写V操作*/
    	}
    
    	if(-1==shmdt((struct use_buf *)shm_buf)){
    		handle_error("shndt"); /*解除当前进程与共享内存的映射*/
    	}	
    	
    	return 0;
    }
    
    优点: 采用同步机制,shm_write进程写后shm_read进程才读,cpu消耗接近零。
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值