Linux进程间通讯|共享内存

共享内存

1. 共享内存概述

共享内存时一种最为高效的进程间通讯方式,因为进程可以直接读写内存,不需要任何数据的负值。为了在多个进程间交换信息,内核专门留出了一块内存区,这段内存区可以由需要访问的进程将其映射到自已的私有空间地址。由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。
共享内存原理示意图.jpg

2. 共享内存编程

2.1 编程说明

共享内存的实现分为两个步骤:

  • 创建共享内存,即从内存中获得一段共享内存区域,使用 shmget() 函数
  • 映射共享内存,即把这段创建的共享内存映射到具体的进程空间中,使用 shmat() 函数
    至此即可使用这段共享内存了,可以使用不带缓冲的I/O读写命令对其进行操作。另外还有撤销内存映射的操作,函数为 shmdt()
2.2 函数介绍

shmget() 创建共享内存函数

/*****shmget()函数*****/
函数原型:int shmget(key_t key, int size, int shmflg)
传 入 值:key 共享内存的键值,多个进程可通过它访问同一个共享内存。IPC_PRIVATE用于创建私有共享内存
		 size 共享内存区大小
		 semflg 同 open() 函数的权限位
返 回 值:成功:返回共享内存标识符;
		 失败:返回-1

shmat() 映射共享内存函数

/*****shmat()函数*****/
函数原型:int shmat(int shmid, const void *shmaddr, int shmflg)
传 入 值:shmid 要映射的共享内存区标识符
		 shmaddr 将共享内存映射到指定地址(若为0表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)
		 semflg 默认为0表示共享内存可读写;SHM_RDONLY表示共享内存只读
返 回 值:成功:被映射的段地址;
		 失败:返回-1

shmdt() 撤销内存映射函数

/*****shmdt()函数*****/
函数原型:int shmdt(const void *shmaddr)
传 入 值:shmaddr 被映射的共享内存段地址
返 回 值:成功:返回0;
		 失败:返回-1
2.3 函数实例
/*****shmem.c*****/
//省略头文件
#define BUFFER_SIZE 2048

int main(){
    
    
	pid_t pid;
	int shmid,
	char *shm_addr;
	char flag[] = "WROTE";
	char *buff;

	if((shmid = shmget(IPC_PRIVATE,BUFFER_SIZE,0666)) < 0){
    
    	//创建共享内存
		perror("shmget");
		exit(1);
	}
	else
		printf("Creat shared-memory: %d\n",shmid);

	system("ipcs -m");	//使用了system()函数调用shell命令“ipcs”,ipcs命令用于报告进程间通讯机制状态
	pid = fork();
	if(pid == -1){
    
    
		perror("fork");
		exit(1);
	}
	else if(pid == 0){
    
    	//子进程
		if((shm_addr = shmat(shmid,0,0)) == (void*)-1){
    
    		//映射共享内存
			perror("Child:shmat");
			exit(1);
		}
		else{
    
    
			printf("Child: Attach shared-memory: %p\n",shm_addr);
		}
		system("ipcs -m");
		
		while(strncmp(shm_addr, flag, strlen(flag))){
    
    
			printf("Child: Wait for enable data...\n");
			sleep(5);
		}

		strcpy(buff, shm_addr + strlen(flag));
		printf("Child: Shared-memory: %s\n",buff);

		if((shmdt(shm_addr)) < 0){
    
    		//解除共享内存映射
			perror("shmdt");
			exit(1);
		}
		else{
    
    
			printf("Child: Deattach shared-memory\n");
		}
		system("ipcs -m");
		
		if((shmctl(shmid, IPC_RMID, NULL)) == -1){
    
    		//删除共享内存
			perror("Child: shmctl(IPC_RMID)\n");
			exit(1);
		}
		else{
    
    
			printf("Delete shared-memory\n");
		}
		system("ipcs -m");
	}
	else{
    
      //父进程
		if((shm_addr = shmat(shmid,0,0)) == (void*)-1){
    
    
			perror("Parent:shmat");
			exit(1);
		}
		else{
    
    
			printf("Parent: Attach shared-memory: %p\n",shm_addr);
		}
		
		sleep(1);
		printf("\nInput some string:\n");
		fgets(buff,BUFFER_SIZE,stdin);
		strncpy(shm_addr + strlen(flag), buff, strlen(buff));
		strncpy(shm_addr, flag, strlen(flag));
		
		if((shmdt(shm_addr)) < 0){
    
    
			perror("Parent shmdt");
			exit(1);
		}
		else{
    
    
			printf("Parent: Deattach shared-memory\n");
		}
		system("ipcs -m");
		
		waitpid(pid, NULL, 0);
		printf("Finished\n");
	}
	exit(0);
}

猜你喜欢

转载自blog.csdn.net/Chuangke_Andy/article/details/108306410