Linux进程间通信(四)--- 共享内存方式

共享内存

共享内存允许两个不相关的进程访问同一个逻辑内存

共享内存方式是传输速度最快的一种。因为共享内存方式将不同进程之间共享的内存安排为同一段物理内存, 客户进程和服务进程传递的数据直接从内存里存取、放入,数据不需要在两进程间复制,再者用共享内存进行数据通信,它对数据格式也没啥限制。

共享内存区域对象的生命周期跟系统内核的生命周期是一致的,而且共享内存区域对象的作用域范围就是在整个系统内核的生命周期之内,即所有访问共享内存区域对象的进程都已经正常结束,共享内存区域对象仍然在内核中存在(除非显式删除共享内存区域对象)。

使用时需要保持不同进程读写同步,可以使用互斥锁或信号量等方式。可以在终端中使用ipcs -m查看系统当前开辟的共享内存

在这里插入图片描述

一、使用
1、头文件
  • #include <sys/ipc.h>
  • #include <sys/shm.h>
2、使用流程及对应的函数原型
  • 创建或获取SHM:int shmget(key_t key, size_t size, int shmflg);
    key:SHM标识
    size:SHM大小
    shmflg:创建或得到的属性,例如IPC_CREAT
    返回值:成功返回shmid,失败返回-1并设置errno

  • 映射SHM到进程地址空间:void *shmat(int shmid, const void *shmaddr, int shmflg);
    shmid:SHM ID
    shmaddr:SHM内存地址
    shmflg:SHM权限
    返回值:成功返回SHM地址,失败返回-1并设置errno
    其中shmaddr的参数主要有2中情况
    Shmaddr=NULL:系统选择一块合适的内存地址作为映射的内存的地址
    Shmaddr!=NULL:用户自己地址

  • 操作映射后的区域,即正常读写

  • 关闭进程地址空间的映射区域:int shmdt(const void *shmaddr)
    shmaddr:已经映射的SHM地址
    返回值:成功返回0,失败返回-1并设置errno

3、基本原理

内核开辟一片内存区域,然后多个用户进程可以将这片区域映射到它们自己的地址空间中进行读写
在这里插入图片描述

二、演示程序
1、Test5-1向共享内存写入内容后test5-2能读到写入的内容,反之亦然
//test5-1
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define SHMSIZE 2048
int main()
{
	pid_t pid;
	pid=fork();
	if(pid!=0)//父进程退出,子进程作为守护进程
		return 0;

	//创建SHM
	//原型;int shmget(key_t key, size_t size, int shmflg);
	int shm_id=shmget(445,SHMSIZE,IPC_CREAT | 0666);
	if(shm_id==-1)//创建SHM失败
	{
		perror("[test5-1]Create shm fail!");
		exit(-1);
	}
	//映射SHM到进程地址空间
	//void *shmat(int shmid, const void *shmaddr, int shmflg);
	void *shm = shmat(shm_id,NULL,0);//内存地址由系统分配,分配成功则返回SHM地址
	if(shm==(void*)-1)//映射失败
	{
		perror("[test5-1]Mat shm fail!");
		exit(-1);
	}

	//写数据到共享空间内
	char str[]="I'm share memory.[Edit by test5-1]";
	memcpy(shm,str,strlen(str)+1);
	printf("[test5-1]Write share memory:%s\n\n",str);

	sleep(10);//等待test5-2读写后,test5-1从中读取

	memcpy(str,shm,strlen(shm)+1);
	printf("[test5-1]Read share memory:%s\n",str);

	shmdt(shm);//关闭SHM

	if (0 == shmctl(shm_id, IPC_RMID,0))
	printf("delete shm success.\n");
	return 0;
}
//test5-2
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define SHMSIZE 2048
int main()
{
	pid_t pid;
	pid=fork();
	if(pid!=0)//父进程退出,子进程作为守护进程
		return 0;

	//创建SHM
	//原型;int shmget(key_t key, size_t size, int shmflg);
	int shm_id=shmget(445,SHMSIZE,IPC_CREAT | 0666);
	if(shm_id==-1)//创建SHM失败
	{
		perror("[test5-2]Create shm fail!");
		exit(-1);
	}
	//映射SHM到进程地址空间
	//void *shmat(int shmid, const void *shmaddr, int shmflg);
	void *shm = shmat(shm_id,NULL,0);//内存地址由系统分配,分配成功则返回SHM地址
	if(shm==(void*)-1)//映射失败
	{
		perror("[test5-2]Mat shm fail!");
		exit(-1);
	}

	
	char str[SHMSIZE];
	memcpy(str,shm,strlen(shm)+1);
	printf("[test5-2]Read share memory:%s\n",str);

	sleep(2);

	//写数据到共享空间内
	char str2[]="I'm share memory.[Edit by test5-2]";
	memcpy(shm,str2,strlen(str)+1);
	printf("[test5-2]Write share memory:%s\n\n",str2);

	sleep(10);//等待test5-2读写后,test5-1从中读取
	shmdt(shm);//关闭SHM
}

运行结果:
在这里插入图片描述
说明:test5-1.c先写再读,test5-2.c先读再写,且严格控制时序,程序比较娇嫩,只作为学习测试共享内存通信。

三、补充总结

要注意共享内存会出现多个进程同时读写,导致数据混乱的情况,因此需要借助信号量或者互斥锁来保障操作的安全。

猜你喜欢

转载自blog.csdn.net/Tong_jy/article/details/86622220
今日推荐