0


Linux | System V 共享内存:工作原理与使用指南

在 Linux 系统中,进程间通信(IPC)是实现多任务环境中不同进程协作的关键技术。在众多的 IPC 机制中,共享内存(Shared Memory)是一种高效的进程间通信(IPC)机制。它允许多个进程共享一个给定的存储区,这些进程可以是父子进程关系或完全无关的进程。共享内存是最快的一种 IPC 形式,因为它允许进程直接对内存进行读写,而不需要数据在内核空间和用户空间之间复制。

一、System V 共享内存概述

进程间通信的本质是让不同进程看到同一个资源。System V 共享内存是一种古老的但依然广泛使用的 IPC 机制,它允许多个进程共享同一块物理内存区域(类似C语言动态库的加载)。这种机制的优势在于,进程可以直接读写内存,无需数据在用户空间和内核空间之间的复制,从而大大提高了数据交换的速度。

二、共享内存的使用方法

核心函数:

  1. **shmget()**:创建或获取一个共享内存段。
  2. **shmat()**:将共享内存段附加到进程的地址空间。
  3. **shmdt()**:将共享内存段从进程的地址空间分离。
  4. **shmctl()**:控制共享内存段(如设置权限)。
1. shmget():创建或获取共享内存段
shmget

函数用于创建一个新的共享内存段或获取对现有共享内存段的访问。如果共享内存段不存在,并且

IPC_CREAT

标志被设置,那么

shmget

将创建一个新的共享内存段。

#include <sys/ipc.h>
#include <sys/shm.h>

int shmid = shmget(key, size, IPC_CREAT | 0666);
  • key:这是一个键值,用于唯一地标识共享内存段。可以通过 ftok 函数从文件路径和项目 ID 生成。
key_t ftok(const char *pathname, int proj_id)
// key_t key = ftok("/tmp", 12345);
  • size:这是要创建的共享内存段的大小,单位为字节。
  • IPC_CREAT:这个标志表示如果共享内存段不存在,则创建它。
  • 0666:这是共享内存段的权限设置,表示所有用户都可以读写共享内存。
2. shmat():将共享内存附加到进程地址空间

一旦共享内存段被创建,进程可以使用

shmat

函数将其附加到自己的地址空间中。这样,进程就可以通过指针直接访问共享内存。

char *ptr = (char *)shmat(shmid, NULL, 0);
  • shmid:由 shmget 返回的共享内存段的标识符。
  • NULL:这个参数指定了共享内存附加的地址。如果传递 NULL,系统会自动选择一个合适的地址。
  • 0:这个标志用于指定附加操作的行为,通常设置为 0。
3. shmdt():将共享内存从进程地址空间分离

当进程不再需要访问共享内存时,可以使用

shmdt

函数将其从地址空间中分离。这不会删除共享内存段,只是断开了进程与共享内存的连接。

int shmdt((const void *)ptr);
  • ptr:这是通过 shmat 函数获得的指向共享内存的指针。
4. shmctl():控制共享内存段
shmctl

函数用于控制共享内存段,如获取其状态信息、设置权限或删除共享内存段。

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid:共享内存段的标识符。
  • cmd:这是要执行的控制操作的命令,如 IPC_STAT 用于获取状态信息,IPC_RMID 用于删除共享内存段。
  • buf:这是一个指向 shmid_ds 结构的指针,用于存储共享内存的状态信息或控制命令的参数。
三、共享内存的使用场景

共享内存适用于以下场景:

  1. 速度快:因为进程可以直接访问内存,无需数据复制。
  2. 简单:使用内存映射文件(memory-mapped files)或系统调用实现。
  3. 容量限制:受限于系统内存和进程地址空间。
四、实践指南与注意事项
  1. 同步机制:由于共享内存本身不提供同步机制,因此在访问共享内存时,应使用信号量或其他同步手段来避免竞态条件。
  2. 内存管理:确保在不再需要共享内存时,及时使用 shmctl 函数删除,避免内存泄漏。
  3. 权限控制:合理设置共享内存的权限,防止未授权访问。
五、示例代码:展示如何使用 System V 共享内存获得其他进程放入共享内存的数据
a. 演示代码头文件
mem.hpp
#include <iostream>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>

const char* pathname = "./main.cc";
using namespace std;
b. 创建和使用共享内存
#include"mem.hpp"

int main()
{
    // 生成内存唯一key值
    key_t key = ftok(pathname, 0666);

    // 创建共享内存段
    int shmid = shmget(key, sizeof(int), 0666 | IPC_CREAT);
    if (shmid < 0)
    {
        cerr << "shmget error" << endl;
        return 1;
    }

    // 将共享内存加载到进程地址空间
    int *ptr = (int *)shmat(shmid, nullptr, 0);
    if (ptr == (int *)(-1))
    {
        cerr << "shmat error" << endl;
        return 2;
    }

    // 分离共享内存
    *ptr = 123;
    cout << "process 1 write> ptr = " << *ptr << endl;
    if(shmdt(ptr) == -1)
    {
        cerr << "shmdt error " << endl;
        return 3;
    }
    sleep(5);

    // 删除共享内存
    if(shmctl(shmid, IPC_RMID, nullptr) == -1)
    {
        cerr << "shmctl error" << endl;
        return 4;
    }

    return 0;
}
c. 另一个进程访问共享内存
#include"mem.hpp"

int main()
{
    // 生成唯一key值
    key_t key = ftok(pathname, 0666);

    // 获取共享内存
    int shmid = shmget(key, sizeof(int), 0666);
    if (shmid < 0)
    {
        cerr << "shmget error " << endl;
        return 1;
    }

    // 将共享内存加载到程序中
    int *ptr = (int *)shmat(shmid, nullptr, 0);
    if (ptr == (int *)-1)
    {
        cerr << "shmat error " << endl;
        return 2;
    }
//
    // 使用共享内存(获得共享内存里的数据)
    cout << *ptr << endl;
//

    // 分离共享内存
    if(shmdt(ptr) == -1)
    {
        cerr << "shmdt error " << endl;
        return 3;
    }

    return 0;
}
标签: linux 服务器 java

本文转载自: https://blog.csdn.net/LiHongyu05/article/details/141832713
版权归原作者 koi li 所有, 如有侵权,请联系我们删除。

“Linux | System V 共享内存:工作原理与使用指南”的评论:

还没有评论