【传输平台】07 共享内存详解及测试案例(本项目进程间的通信手段)

本项目使用共享内存来进行进程间通信。
**划重点:**学习Linux的进程间通信(不局限于进程间通信),我们应该站在Linux内核的角度去看待。
皮毛都不怎么懂,我还需努力。

01 管道/消息队列传递数据与用共享内存传递数据比较

001 用管道/消息队列传递数据
在这里插入图片描述
如上图需要四步:
(1)服务器读文件;
(2)服务器把数据给内核,内核缓存下来;
(3)客户端从内核中取数据;
(4)客户端写文件。

002 用共享内存传递数据
在这里插入图片描述
共享内存
进程像使用自己的堆区,栈区一样使用内核
(1)服务器把文件拷贝到共享内存
(2) 客户端直接从共享内存拿数据
所以共享内存是最快的IPC 进程间通信方式

02 共享内存理论知识

这块不是重点: 直接去linux 使用man指令观看

共享内存:是被多个进程共享的一部分物理内存,共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以理解看到其中的内容。

共享内存实现实现分为两个步骤:
一:创建共享内存,使用shmget函数
二:映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数

创建:
int shmget(key_t key,int size,int shmflg)
key标识共享内存的键值:0/IPC_PRIVATE。当key的取值为IPC_PRIVATE,则函数shmget()将创建一个新的共享内存;如果key的取值为0,而参数shmflg中又设置IPC_PRIVATE这个标志,则同样会创建一块新的共享内存。
返回值:如果成功则返回内存标识符,如果失败则返回-1;

映射:
int shmat(int shmid, char *shmaddr,int flag)
参数:
shmid:shmget函数返回的共享内存存储标识符
flag:决定以后用什么方式来确定映射地址(通常为0)
返回值:
如果成功,则返回共享内存到进程中的地址;如果失败,则返回-1

一个进程不再需要共享内存时,需要把它从进程地址空间中脱离。

03 样例

我们直接上代码:

```cpp
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <sys/ipc.h>
#include <sys/shm.h>

// int shmget(key_t key, size_t size, int shmflg);
void main40()
{	
	int 		shmid;
	//打开共享内存 若存在,则使用;若不存在 则报错
	//打开文件 若文件存在,则使用 若文件不存在则报错
	shmid = shmget(0x2232, 128, 0666 );
	if (shmid < 0)
	{
		printf("获取共享内存失败\n");
		return ;
	}
	printf("获取共享内存ok\n");
	printf("hello....\n");	
}

void main41()
{	
	int 		shmid = 0;
	//打开共享内存 若存在,则使用;若不存在 则创建
	//打开文件 	若文件存在,则使用 若文件不存在,则创建
	shmid = shmget(0x1133, 1024, 0666|IPC_CREAT);
	if (shmid < 0)
	{
		printf("获取共享内存失败\n");
		return ;
	}
	printf("创建共享内存成功 ok\n");
	printf("hello....\n");	
}

void main42()
{	
	int 		shmid = 0;
	//打开共享内存 若存在,则报错;若不存在 则创建
	//打开文件 	若文件存在,报错 若文件不存在,则创建
	//避免把旧的共享内存
	shmid = shmget(0x4000, 1024, 0666|IPC_CREAT | IPC_EXCL);
	if (shmid < 0)
	{
		printf("获取共享内存失败\n");
		return ;
	}
	printf("创建共享内存成功 ok\n");
	printf("hello....\n");	
}

/*

   void *shmat(int shmid, const void *shmaddr, int shmflg);

       int shmdt(const void *shmaddr);
       */
void main()
{	
	int 		shmid = 0;
	//打开共享内存 若存在,则使用;若不存在 则创建
	//打开文件 	若文件存在,则使用 若文件不存在,则创建
	shmid = shmget(0x2222, 1024, 0666|IPC_CREAT);
	if (shmid < 0)
	{
		printf("获取共享内存失败\n");
		return ;
	}
	printf("创建共享内存成功 ok\n");
	printf("hello....\n");	
	

	//连接共享内存
	char * p = shmat(shmid, NULL, 0);
	
	strcpy(p, "12345678");
	
	printf("p:%s \n", (char *)p);
	
	
	printf("任意键反连接共享内存,并且删除共享内存\n");
	getchar();
	
	//取消连接共享内存
	shmdt((void *)p);
	
	//删除共享内存
  	//int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  	shmctl(shmid, IPC_RMID, NULL);
}

(1)使用main40 进行结果演示:
运行之前:
在这里插入图片描述
看一下没有0x2232 键的共享内存段,因此结果应该是失败
在这里插入图片描述
注意这块不存在该键的共享内存,以及字节大小小于main40要求的128字节,都会是获取共享内存失败。
(2)使用main41 进行结果演示
在这里插入图片描述
(3)直接使用上述的代码不进行更改:就是使用main进行结果演示
代码步骤是:1》创建共享内存 ; 2》连接共享内存 ;3》向里面拷贝数据;4》取消连接共享内存;5》关闭共享内存
在这里插入图片描述
看到创建了共享内存,并在里面有一个连接在运行。
当我们输入任意键之后结果如下:
在这里插入图片描述
直接删除。

04 思考一下当3个进程同时使用一块内存空间,当其中一个进程要求删除内存空间时会产生什么结果?

在这里我们的测试代码还是使用上述的原代码不进行更改,在linux中./(运行)三次就可以创建三个进程。
(1)运行前,无共享内存段:
在这里插入图片描述
(2)运行三次:
在这里插入图片描述
看一下在这个共享内存块中有三个连接。
(3)让其中一个删除共享内存
在这里插入图片描述
让其中一个进程断掉连接后,删除共享内存我们会发现连接数变为2,键值变为0X00000000。
等于说当多个进程连接同一个共享内存段的时候,其中一个连接删除共享内存,那么其他的连接会被系统自动转存到键为0X00000000的共享内存段中去。
我们要知道该键值的共享内存段是Linux内核私有的,不能被其它进程进行连接。(这些设计linux内核的大佬真厉害)

05 优缺点:

本篇文章优缺点不做重点,这块是查看的其他人的博客
https://www.cnblogs.com/wuyepeng/p/9748889.html
(1)优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。

(2)缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章