仓库地址https://gitee.com/tgwTTT/linux-learning-dai/tree/master/Shm

一、共享内存的原理与OS管理

共享内存是操作系统提供的一种高效进程间通信(IPC)机制。所有的底层管理工作都由操作系统自动完成,包括内存分配、映射、权限控制和资源回收。我们只需要通过系统调用完成创建、连接、读写和删除等操作。

取消关联关系后,OS会自动释放进程的虚拟地址映射,但共享内存本身的物理空间只有在明确删除后才会被释放。
一个共享内存段可以被多个进程同时映射和访问,实现数据共享。


二、系统调用与参数说明

1. 常用系统调用

  • shmget(key, size, shmflg):创建或获取共享内存段。
  • shmat(shmid, addr, flag):将共享内存映射到进程虚拟地址空间。
  • shmdt(addr):解除映射关系(detach)。
  • shmctl(shmid, IPC_RMID, 0):删除共享内存段。

2. 命令行工具

  • ipcs -m:查看当前系统所有共享内存段。
  • ipcrm -m :删除指定的共享内存段。

注意:
即使进程退出,只要没有删除共享内存段,资源会一直存在,生命周期随内核。

三、代码举例

用了共享内存作为数据交换区,server 进程负责创建共享内存并读取数据,client 进程负责连接共享内存并写入数据。
为保证同步,配合 FIFO 管道实现唤醒通知

  1. 共享内存管理(Shm.hpp)
    Shm 类封装了共享内存的创建、连接、映射和销毁。
    server 用 CREATER 模式创建,client 用 USER 模式连接。

部分代码举例:

  void Attach()
    {
        _start_mem = shmat(_shmid, nullptr, 0);
        if ((long long)_start_mem < 0)
        {
            ERR_EXIT("shmat");
        }
        printf("attach success\n");
    }
    void Detach()
    {
        int n = shmdt(_start_mem);
        if (n == 0)
        {
            printf("detach success\n");
        }
    }
void CreateHelper(int flg)
    {
        printf("key: 0x%x\n", _key);
        // 共享内存的生命周期,随内核
        _shmid = shmget(_key, _size, flg);
        if (_shmid < 0)
        {
            ERR_EXIT("shmget");
        }
        printf("shmid: %d\n", _shmid);
    }
Shm(const std::string &pathname, int projid, const std::string &usertype)
        : _shmid(gdefaultid),
          _size(gsize),
          _start_mem(nullptr),
          _usertype(usertype)
    {
        _key = ftok(pathname.c_str(), projid);
        if (_key < 0)
        {
            ERR_EXIT("ftok");
        }
        if (_usertype == CREATER)
            Create();
        else if (_usertype == USER)
            Get();
        else
        {
        }
        Attach();
    }
    void *VirtualAddr()
    {
        printf("VirtualAddr: %p\n", _start_mem);
        return _start_mem;
    }
    int Size()
    {
        return _size;
    }
    void Attr()
    {
        struct shmid_ds ds;
        int n = shmctl(_shmid, IPC_STAT, &ds); // ds:输出型参数
        printf("shm_segsz: %ld\n", ds.shm_segsz);
        printf("key: 0x%x\n", ds.shm_perm.__key);
    }

  

今天的更新就到这里,如有错误欢饮指出!!