共享内存实例

writer.cpp 如下:

#include <iostream>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define SHM_KEY 0x1234
#define BUF_SIZE 1024

struct ShmRingBuffer
{
        unsigned int write_index;
        unsigned int read_index;
        char buffer[BUF_SIZE];
};

int main()
{

    //SHM_KEY: 共享内存标识 ;  0666:读写权限 ; IPC_CREAT:如果不存在就创建
    int shmid = shmget(SHM_KEY, sizeof(ShmRingBuffer), 0666 | IPC_CREAT);
    if (shmid < 0)
    {
        perror("shmget");
        return -1;
    }

      //shmat作用:把内核里的共享内存,映射到当前进程的虚拟地址空间

      //成功之后:shm 就是一个普通结构体指针

    ShmRingBuffer* shm = (ShmRingBuffer*)shmat(shmid, NULL, 0);

    // 初始化(第一次运行)
    shm->write_index = 0;
    shm->read_index = 0;

    const char* msg = "Hello Shared Memory!";
    int len = strlen(msg);

    // 判断剩余空间
    unsigned int free_space;
    if (shm->write_index >= shm->read_index)
        free_space = BUF_SIZE - (shm->write_index - shm->read_index);
    else
        free_space = shm->read_index - shm->write_index;

    if (free_space <= len)
    {
        std::cout << "Buffer full!" << std::endl;
        return -1;
    }

    // 写入(环形)
    for (int i = 0; i < len; i++)
    {
        shm->buffer[shm->write_index] = msg[i];

        //严格环形缓冲区通常要保留1字节,否则无法区分“满”和“空”。
        shm->write_index = (shm->write_index + 1) % BUF_SIZE;
    }

    std::cout << "Write Done\n";

    shmdt(shm);
    return 0;
}

reader.cpp 如下:

#include <iostream>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define SHM_KEY 0x1234
#define BUF_SIZE 1024

struct ShmRingBuffer
{
            unsigned int write_index;
                unsigned int read_index;
                    char buffer[BUF_SIZE];
};
int main()
{
    int shmid = shmget(SHM_KEY, sizeof(ShmRingBuffer), 0666);
    if (shmid < 0)
    {
        perror("shmget");
        return -1;
    }

      //把内核中的共享内存映射到当前进程地址空间

    ShmRingBuffer* shm = (ShmRingBuffer*)shmat(shmid, NULL, 0);

    char data[128] = {0};
    int i = 0;

    while (shm->read_index != shm->write_index)
    {
        data[i++] = shm->buffer[shm->read_index];
        shm->read_index = (shm->read_index + 1) % BUF_SIZE;
    }

    std::cout << "Read Data: " << data << std::endl;

    shmdt(shm);
    return 0;
}

环形队列(Ring Buffer)是共享内存通信中最经典、最高效的数据结构之一:

一、环形队列的核心思想

一句话概括:

用一块固定大小的连续内存,通过“读指针”和“写指针”循环移动,实现不断复用空间的队列结构。

核心元素只有两个:

read_index   // 读位置
write_index  // 写位置

以及一个固定数组:

buffer[N]

三、环形的真正价值:

1️⃣ 空间完全复用

普通数组:

用过的前半段浪费。

环形数组:

读过的空间立即可复用。

2️⃣ O(1) 时间复杂度

入队:

buffer[write] = data
write++

出队:

data = buffer[read]
read++

没有:

  • 内存移动

  • realloc

  • malloc

性能极高

3️⃣ 非常适合生产者-消费者模型

共享内存典型模型:

生产者(写进程)
消费者(读进程)

只要保证:

读写不同索引:

就可以:

  • 无锁(单生产者单消费者)

  • 极低延迟

  • 高吞吐

四、为什么共享内存必须用环形队列?
如果不用环形,你会遇到问题:

❌ 1. 需要移动内存

比如:

memmove(buffer, buffer + read_index, 剩余长度)

这样:

  • CPU 消耗大

  • 多进程下风险高

  • 性能极差

❌ 2. 需要动态扩展

共享内存大小是固定的:

shmget(size)

不能随便扩容。

环形结构刚好适配“固定大小”的限制。

❌ 3. 数据会丢失或浪费

如果不用环形:

  • 写满后必须停止

  • 或重新申请

这对实时系统是灾难。

它模拟的是:

流水线

六、核心数学模型

定义:

空:read == write

数据长度:
(write - read + size) % size

剩余空间:
(size - 数据长度 - 1)

这里的:

+ size
% size

是为了处理回绕。

七、为什么不用链表?

链表环形数组
需要 malloc固定内存
不连续连续内存
cache不友好cache友好
多进程复杂多进程简单

八、什么时候环形队列最强?

最典型场景:

  • 串口通信

  • 网络收发

  • 日志缓冲

  • 音视频流

  • 嵌入式系统

  • 多进程通信

九、核心思想总结

环形队列的核心思想是:

  1. 用固定空间

  2. 用两个指针

  3. 通过取模实现空间循环

  4. 避免内存移动

  5. 实现高效生产者-消费者通信

十、再给一句终极总结

普通队列是:

空间向前增长

环形队列是:

指针向前走,空间在循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值