API
共享内存通常是通过 POSIX API 或 System V API 来管理。C++中可以使用这两种方式实现共享内存。
- System V提供了一些基础的IPC机制,但它没有统一的标准,且实现细节和兼容性可能存在差异。
- POSIX标准是在System V的基础上发展而来,旨在为不同操作系统提供一致的接口。POSIX通常会尽量使得跨平台编程变得更加简洁和一致。
所谓共享内存通信,实际上就是在内核空间中有一个缓存数组,用于不同用户进程间实现通信。其处理思想和文件IO思想是一样的,也是open、write、read、close函数,只是函数形式方式了变化。
共享内存生命周期随内核,共享没有自带同步或互斥,由用户来维护共享内存,信号量共享内存通常结合在一起使用
POSIX
1.创建/打开共享内存
int shm_open(const char* name ,int oflag,mode_t mode);
name:共享对象的名称,必须以/开头
oflag:打开共享内存的标志
O_CREATE:如果共享内存不存在则创建它
O_RDWR:以读写模式打开
O_EXCL:与O_CREATE一起使用,如果共享内存已存在,则返回错误
mode:权限,通常0666表示可读写
返回值:成功返回共享内存的标识符,否则-1
2.设置共享内存大小
int ftruncate(inf fd,off_t length);
fd:共享内存对象的文件描述符,由shm_open返回
length:设置共享内存大小
设置共享内存的大小时,通常推荐使用页面大小的倍数,4KB 是大多数操作系统下的标准内存页面大小;有助于提高性能,避免内存碎片化
3.映射共享内存
使用mmap()将共享内存映射到进程的地址空间中,映射完之后就可使用内存了
void* mmap(void *addr,size_t length,int port,int flags,int fd,off_t offset);
addr:建议的映射启始地址,通常传NULL,让系统自动选择
length:映射区域的大小
port:内存保护标志,常用的有:PROT_READ/PORT_WRITE,也内容可读/写
flags:映射标志:
MAP_SHARED:所映射的内存共享,不同进程可共享,比如一个进程读,一个进程写选择
MAP_PRIVITE:私有内存,修改的数据其他数据不可见,适用场景少
offset: 偏移量,通常设置0
4.释放共享内存
当不需要访问共享内存是,应先解除映射,再删除
int munmap(void *add,size_t length);
addr:指向共享内存的指针
length:映射的长度
demo例子:
#include <sys/mman.h>
#include <sys/stat.h>
// client 写
int main(){
int shm_fd = shm_open("/myshared_mem",O_CREATE | O_RDWR,0666);
if(shm_fd == -1) {
return 1;
}
if(ftruncate(shm_fd,4000)==-1)
return 1;
void *shm_ptr = mmap(NULL,4000,PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);
if(shm_ptr == MAP_FAILED)
return 1;
return 0;
// 释放。。。
}
// server 读
int main() {
int shm_fd = shm_open("/myshared_mem",O_RDONLY,0666);
if(shm_fd == -1)
return 1;
void *shm_ptr = mmap(NULL,4000,PROT_READ,MAP_SHARED,shm_fd,0);
if(shm_ptr == MAP_FAILD)
return 1;
char *msg = (char*)shm_ptr;
std::cout << "msg:" << msg << "\n";
//写内存
const char* msg = "HELLO,Shared Memory";
memcpy(shm_ptr,msg,strlen(mgs)+1);
//释放
if(munmap(shm_ptr,4000)==-1)
return 1;
if(shm_unlink("/myshard_mem")==-1)
return 1;
}
应用
client定时可写入不同数据结构,server定时读取.
实现方式:环形buffer + 信号量
class SharedMem {
public:
SharedMem(const char*name,bool create){
sem = shm_open(name,);
if(create && truncate()){
}
ptr = mmap();
}
privite:
sem_t* sem;
void* ptr;
};