共享内存(Shared Memory)是Linux系统中一种高效的进程间通信(IPC)机制,允许多个进程共享同一块物理内存区域,从而实现快速的数据交换。本文将提供完整的C++代码示例,包括头文件、客户端和服务端实现,详细展示共享内存的创建、使用、同步及管理过程。✨
共享内存是Linux系统进程间通信(IPC)中最快的一种方式,其核心思想是让多个进程通过映射同一块物理内存来实现数据共享。
shmctl
或使用ipcrm
命令删除 ️#include
key_t ftok(const char *pathname, int proj_id);
pathname
:已存在的文件路径(如/home/user/config
)proj_id
:项目ID(0-255) int shmget(key_t key, size_t size, int shmflg);
IPC_CREAT
:不存在则创建 IPC_EXCL
:配合IPC_CREAT
使用,存在则报错 ❌0666
)void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
shmaddr
设为NULL
由系统选择地址 SHM_RDONLY
以只读方式挂接 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
IPC_STAT
:获取状态信息 IPC_RMID
:标记删除 ️以下是实现共享内存通信的完整代码,分为三个文件:common.hpp
(公用头文件)、client.cc
(客户端)和server.cc
(服务端)。
common.hpp
#ifndef __COMMON_HPP__
#define __COMMON_HPP__
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const string pathname = "/home"; // ftok使用的路径名
const int proj_id = 0x666; // ftok的项目ID
const string FIFO_FILE = "./myfifo"; // 命名管道文件路径
const mode_t MODE = 0664; // 命名管道权限
enum Mistake
{
FTOK_ERROR = 1,
SHMGET_ERROR,
SHMAT_ERROR,
FIFO_CREATE_ERR,
FIFO_DELETE_ERR
};
// 生成唯一的key_t键值
key_t GetKey()
{
key_t key = ftok(pathname.c_str(), proj_id);
if (key < 0)
{
perror("ftok error");
exit(FTOK_ERROR);
}
return key;
}
// 共享内存辅助函数 ️
int GetShareMemHelper(int flag)
{
key_t key = GetKey();
int shmid = shmget(key, 4096, flag); // 创建或获取4096字节的共享内存
if (shmid < 0)
{
perror("shmget error");
exit(SHMGET_ERROR);
}
return shmid;
}
// 创建共享内存
int CreateShm()
{
return GetShareMemHelper(IPC_CREAT | IPC_EXCL | 0666);
}
// 获取共享内存
int GetShm()
{
return GetShareMemHelper(IPC_CREAT);
}
// 初始化类:创建和销毁命名管道
class Init
{
public:
Init()
{
int n = mkfifo(FIFO_FILE.c_str(), MODE);
if (n == -1 && errno != EEXIST) // 如果管道已存在则忽略错误 ⚠️
{
perror("mkfifo");
exit(FIFO_CREATE_ERR);
}
}
~Init()
{
int m = unlink(FIFO_FILE.c_str());
if (m == -1)
{
perror("unlink");
exit(FIFO_DELETE_ERR);
}
}
};
#endif
client.cc
#include "common.hpp"
int main()
{
// 获取共享内存
int shmid = GetShm();
char *shmaddr = (char *)shmat(shmid, nullptr, 0);
if (shmaddr == (char *)-1)
{
perror("shmat error");
exit(SHMAT_ERROR);
}
// 打开命名管道并发送信号
int fd = open(FIFO_FILE.c_str(), O_WRONLY);
if (fd < 0)
{
perror("open");
exit(1);
}
cout << "Please Enter :" << endl;
// 从标准输入读取数据并写入共享内存 ⌨️
while (true)
{
fgets(shmaddr, 4096, stdin);
write(fd, "c", 1); // 通知服务端数据已写入
}
// 分离共享内存
shmdt(shmaddr);
close(fd);
return 0;
}
server.cc
#include "common.hpp"
int main()
{
// 创建命名管道
Init init;
// 创建共享内存
int shmid = CreateShm();
char *shmaddr = (char *)shmat(shmid, nullptr, 0);
if (shmaddr == (char *)-1)
{
perror("shmat error");
exit(SHMAT_ERROR);
}
// 打开命名管道,等待客户端信号
int fd = open(FIFO_FILE.c_str(), O_RDONLY);
if (fd < 0)
{
perror("open");
exit(1);
}
std::cout << "server start sucess" << endl;
while (true)
{
char c;
ssize_t s = read(fd, &c, 1); // 读取信号
if (s <= 0)
break; // 当s小于0说明写端关闭跳出循环关闭共享内存
else if (s > 0)
{
cout << "client say@ " << shmaddr; // 输出共享内存内容 // 获取共享内存状态
struct shmid_ds shmds;
shmctl(shmid, IPC_STAT, &shmds);
cout << "shm size: " << shmds.shm_segsz << endl;
cout << "shm nattch: " << shmds.shm_nattch << endl;
printf("shm __key: 0x%x\n", shmds.shm_perm.__key);
cout << "shm shm_perm.mode: " << shmds.shm_perm.mode << endl;
cout << "---------------------" << endl;
}
}
// 分离并删除共享内存 ️
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, nullptr);
close(fd);
return 0;
}
g++ -o client client.cc
g++ -o server server.cc
在一个终端运行服务端:
./server
在另一个终端运行客户端:
./client
在客户端终端输入消息(例如"Hello, shared memory!"
)并按回车 ↵
共享内存创建与附加
shmget
创建共享内存,客户端通过相同的键值获取。shmat
将共享内存映射到进程地址空间,返回指针供直接操作。数据通信
同步机制 ⚡
资源管理 ️
shmctl(IPC_RMID)
删除共享内存,Init
类的析构函数清理命名管道。