目录
共享内存概述
共享内存函数
(1)shmget函数
功能概述
函数原型
参数解释
返回值
示例
结果
(2)shmat函数
功能概述
函数原型
参数解释
返回值
(3)shmdt函数
功能概述
函数原型
参数解释
返回值
示例1(所有函数结合总示例)
结果
示例2(内存偏移存取数据)
结果
共享内存概述
共享内存在进程间传输数据的效率极高。
概念:在物理内存中开辟一块区域,让多个进程能将其映射到各自虚拟地址空间,实现对同一块内存的共享访问。
原理:先由进程创建共享内存获标识符,其他进程再将其映射到自身地址空间,然后进程就能像访问普通内存一样对其进行读写操作。
优点:数据传输快,因为无需像其他通信方式那样进行数据复制;能支持大量数据传输,适合对大块数据的频繁访问。
缺点:需进程自行处理同步和互斥问题,以避免数据冲突;使用不当易引发程序错误和内存泄漏,且不支持跨机器的进程通信。
应用场景:常用于对通信速度要求高的场景,如实时数据处理系统、数据库系统中的缓冲区管理等。
共享内存函数
(1)shmget函数
功能概述
shmget
是一个用于创建或获取共享内存段的系统调用,主要用于在类 Unix 系统(如 Linux)中实现进程间通信(IPC)
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
参数解释
key
:用于标识共享内存段的键值。它可以是通过ftok
函数生成的唯一键值,也可以是IPC_PRIVATE
。若为IPC_PRIVATE
,则会创建一个新的、私有的共享内存段,该共享内存段只能由创建它的进程及其子进程访问。
size
:指定要创建或获取的共享内存段的大小,以字节为单位。若要创建新的共享内存段,此参数必须大于 0。
shmflg
:一组标志位,用于控制共享内存段的创建和访问权限。常见标志如下:
IPC_CREAT
:若指定的共享内存段不存在,则创建它。
IPC_EXCL
:与IPC_CREAT
一起使用时,若共享内存段已存在,函数会失败并返回 -1。权限标志:如0666
,用于设置共享内存段的访问权限,类似于文件的权限设置。
返回值
若调用成功,返回一个非负整数,即共享内存段的标识符(shmid
),后续的共享内存操作会使用这个标识符。
若失败,返回 -1,并设置 errno
来指示错误类型。
示例
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
using namespace std;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
int main()
{
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
return 0;
}
结果
下面第二个就是我们创建的共享内存
(2)shmat函数
功能概述
shmat
函数是类 Unix 系统(如 Linux)中用于将共享内存段附加到调用进程的地址空间的系统调用,通过它进程可以像访问自身内存一样访问共享内存段。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数解释
shmid
:这是由shmget
函数返回的共享内存段标识符,用于指定要附加的共享内存段。
shmaddr
:它指定共享内存段要附加到的进程地址空间的地址。一般可设置为NULL
,让系统自动选择合适的地址进行附加。
shmflg
:这是一组标志位,用于控制附加操作的行为,常见标志如下:
SHM_RDONLY
:以只读模式附加共享内存段,即进程只能读取共享内存中的数据,不能进行写入操作。
0
:以读写模式附加共享内存段。
返回值
若调用成功,返回指向共享内存段在进程地址空间中起始地址的指针,后续进程可通过该指针访问共享内存段。
若失败,返回 (void *)-1
,并设置 errno
来指示错误类型。
(3)shmdt函数
功能概述
shmdt
函数在类 Unix 系统里用于将共享内存段从调用进程的地址空间分离。分离后,进程就无法再通过之前附加时得到的指针来访问该共享内存段,但共享内存段本身并不会被删除,其他仍附加了该共享内存段的进程依旧可以访问它。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
参数解释
shmaddr
:这是一个指向共享内存段在进程地址空间中起始地址的指针,该指针是之前调用 shmat
函数时返回的。
返回值
若调用成功,返回 0
。
若失败,返回 -1
,同时设置 errno
以指示错误类型。
示例1(所有函数结合总示例)
Amain.cpp发送数据
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
int main()
{
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
// 链接共享内存
shmaddr = shmat(shmid, NULL, 0);
// 共享内存写入数据
STU stu = { "2019211001", "zhangsan" };
memcpy(shmaddr, &stu, sizeof(STU));
// 断开链接共享内存
shmdt(shmaddr);
}
return 0;
}
Bmain.cpp接收数据
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
int main()
{
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU), IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
// 链接共享内存
shmaddr = shmat(shmid, NULL, 0);
// 共享内存取数据
STU stu = { 0 };
memcpy(&stu, shmaddr, sizeof(STU));
cout << "学号:" << stu.stuid << endl;
cout << "姓名:" << stu.stuname << endl;
memset(shmaddr, 0, sizeof(STU)); // 清空共享内存数据
// 断开链接共享内存
shmdt(shmaddr);
}
return 0;
}
注:因为是对内存直接操作,所以在取完数据之后记得清空内存
结果
示例2(内存偏移存取数据)
Amain.cpp
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
int main()
{
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU)*3, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
// 链接共享内存
shmaddr = shmat(shmid, NULL, 0);
// 共享内存写入数据
STU stu = { 0 };
for (int i = 1; i < 4; i++)
{
sprintf(stu.stuid, "%d", i);
sprintf(stu.stuname, "name%d", i);
memcpy(shmaddr + sizeof(STU) * (i - 1), &stu, sizeof(STU));
}
// 断开链接共享内存
shmdt(shmaddr);
}
return 0;
}
Bmain.cpp
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
int main()
{
void* shmaddr = NULL;
int shmid = shmget((key_t)1002, sizeof(STU)*3, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmget error");
}
else
{
// 链接共享内存
shmaddr = shmat(shmid, NULL, 0);
// 共享内存取数据
STU stu = { 0 };
for (int i = 1; i < 4; i++)
{
memcpy(&stu, shmaddr + sizeof(STU) * (i - 1), sizeof(STU));
cout << "次数" << i << "学号:" << stu.stuid << endl;
cout << "次数" << i << "姓名:" << stu.stuname << endl;
}
memset(shmaddr, 0, sizeof(STU)); // 清空共享内存数据
// 断开链接共享内存
shmdt(shmaddr);
}
return 0;
}