共享内存POSIX

76 阅读3分钟

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;
};