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消耗接近零。
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章