目录
一、前言
二、什么是共享内存
三、共享内存的创建及使用
1、shmget()函数
2、shmat()函数
3、shmdt()函数
四、使用共享内存实现进程间通信
1、准备一个写端
2、准备一个读端
3、测试结果
一、前言
进程间通信(IPC,InterProcess Communication) 是指在不同进程之间传播或交换信息,现在linux使用的进程间通信方式有:(1)管道(pipe)和命名管道(FIFO) (2)信号(signal) (3)消息队列 (4)共享内存 (5)信号量 (6)套接字(socket)。
之前介绍了信号、管道,今天我们来学习一下共享内存是如何进行进程间的通信。
二、什么是共享内存
- 共享内存图示
文章图片
共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中,其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。如上图所示。
注:
文章图片
:共享内存可以由某个进程创建,但共享内存不属于任何一个进程
文章图片
:共享内存属于操作系统,由操作系统管理
文章图片
:所有进程都可以访问共享内存地址,就好像它们是有malloc分配的一样
文章图片
:如果一个进程向这段共享内存写了数据,所做的改动会立刻被有权访问同一段共享内存的其他进程看到
- 在linux终端输入命令:ipcs可以查看当前系统的消息队列、共享内存段、信号数量组
文章图片
之前使用的命名管道FIFO最大传输量为65535字节,而且用到的 fifo“文件”容易被用户误删,这样就会导致进程间的通信发生错误
文章图片
,共享内存允许两个不相关的进程去访问同一部分逻辑内存,效率极高
文章图片
,所以接下来介绍一下共享内存如何用代码创建并且去使用它。
三、共享内存的创建及使用 1、shmget()函数
- 函数功能:创建共享内存(不存在)或获取共享内存(存在)。
#include示例:
#include
函数原型:
int shmget(key_t key, size_t size, int shmflg);
参数:
key:(非0整数),它有效地为共享内存段命名
size:需要共享的内存量
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:
如果共享内存创建成功,返回一个非负整数,即该段共享内存的标识码;
如果失败,则返回 -1 。
- 创建一个共享内存
#include
#include
#include
#include using namespace std;
int main()
{
int shmid = 0;
//不存在则创建共享内存,存在则获取
shmid = shmget((key_t)1001, 10086, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
cout << "创建共享内存成功" << endl;
} return 0;
}
- 通过命令:ipcs ,可以看见我们新创建出来的共享内存段,权限为777,字节数为10086。
文章图片
- ipcrm -m shmid删除共享内存
- Ipcrm -a全部删除除了系统原本root创建的内存段
文章图片
2、shmat()函数
- 函数功能:第一次创建完共享内存时,它还不能被任何进程访问,shmat ()函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
#include3、shmdt()函数
#include
函数原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:通过shmget()函数返回的共享内存标识
shmaddr:把共享内存连接到当前进程去的时候准备放置它的那个地址
shmflg:可以指定为0,
返回值:
成功:返回一个指针,指针指向共享内存的第一个字节,也就是共享内存的首地址
失败:则返回 -1 。
- 函数功能:把共享内存与当前进程脱离开
#include注:
#include
函数原型:
int shmdt(const void *shmaddr);
参数:
shmaddr:由shmat()函数返回的地址指针
【linux远程开发|linux远程开发——(IPC通信)共享内存的使用】返回值:
成功:返回 0 ,
失败:返回 -1 。
文章图片
:使用shmdt()函数脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已
四、使用共享内存实现进程间通信 下面通过一个小例子来使用共享内存实现两个不相关进程间的简单通信。
1、准备一个写端
- 向共享内存写入数据,写入的数据为{ "10001","admin" };
#include
#include
#include
#include
#include
using namespace std;
typedef struct student
{
char id[10];
char name[10];
}STU;
int main()
{
STU stu = { "10001","admin" };
void* shamdaddr = NULL;
int shmid = 0;
//不存在则创建共享内存,存在则获取
shmid = shmget((key_t)1001, 10086, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
//连接共享内存,首地址存到 shamdaddr
shamdaddr = shmat(shmid, NULL, 0);
memcpy(shamdaddr, &stu, sizeof(STU));
//内存拷贝 即:将stu结构体的数据写入共享内存中
cout << "写入数据成功" << endl;
//结束连接 当前进程脱离共享内存
shmdt(shamdaddr);
}
return 0;
}
2、准备一个读端
- 读取共享内存的数据,存到一个空的结构体中。
#include
#include
#include
#include
#include
using namespace std;
typedef struct student
{
char id[10];
char name[10];
}STU;
int main()
{
STU stu = { 0 };
void* shamdaddr = NULL;
int shmid = 0;
//不存在则创建共享内存,存在则获取
shmid = shmget((key_t)1001, 10086, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
//连接共享内存,首地址存到 shamdaddr
shamdaddr = shmat(shmid, NULL, 0);
memcpy(&stu, shamdaddr, sizeof(stu));
//内存拷贝 即:将共享内存中的数据写入空的结构体中
cout << "获取数据成功" << endl;
cout << stu.id << endl;
cout << stu.name << endl;
//结束连接 当前进程脱离共享内存
shmdt(shamdaddr);
}
return 0;
}
两个工程的代码都差不多,区别是一个写数据,一个读数据。
3、测试结果
- 在linux下通过g++的方式进行编译,在用 ./ 的方式运行,测试结果如下
文章图片
读写正常
文章图片
文章图片
共享内存段也正常创建出来,连接数为0,是因为程序运行结束了。
文章图片
文章图片
共享内存里的数据没有做改动会一直存在,重复读取内容是可以读取到的。
文章图片
原创不易,转载请标明出处。
对您有帮助的话可以一键三连,会持续更新的(嘻嘻)。
推荐阅读
- linux远程开发|linux远程开发——信号的使用(信号绑定和发送)
- linux远程开发|linux远程开发——使用vs2019远程连接linux
- linux|Asahi Linux 初版发布,面向所有用户开放下载
- Linux|传输层TCP与UDP
- Linux|Linux编程——网络编程
- Linux|Linux socket编程(C语言socket实现客户端与服务器网络通信)
- linux远程开发|linux远程开发——网络通信(客户端与服务器建立连接)
- Linux之fgrep命令
- OpenWrt|OpenWrt学习总结(2)编译OpenWrt过程中整理的软件包下载网址