当前位置: 首页 > news >正文

共享内存详细解释

1. 什么是共享内存?

共享内存是 Linux 系统提供的一种高效的**进程间通信(IPC,Inter-Process Communication)**机制。它允许多个进程访问同一块物理内存区域,从而实现数据共享和通信。相比其他 IPC 机制(如管道、消息队列或套接字),共享内存的优点是速度快,因为数据不需要在内核态和用户态之间频繁拷贝,只需在共享内存区域直接读写。

共享内存的核心思想是:多个进程将同一块物理内存映射到各自的虚拟地址空间,从而可以像访问自己的内存一样访问这块共享区域。


2. 为什么跨进程可以共享同一块内存?

要理解为什么共享内存可以跨进程通信,我们需要从操作系统的内存管理和进程模型讲起。

2.1 进程的虚拟内存

在 Linux 中,每个进程都有自己的虚拟地址空间,进程看到的内存地址是虚拟地址,而不是实际的物理地址。虚拟地址通过**页表(Page Table)**映射到物理内存。操作系统通过内存管理单元(MMU)将虚拟地址转换为物理地址。

2.2 共享内存的实现原理

共享内存的实现依赖于操作系统的内存映射机制。具体来说:

  • 当多个进程需要共享内存时,操作系统会将同一块物理内存映射到这些进程的虚拟地址空间中。
  • 每个进程的虚拟地址可能不同,但它们指向的物理内存是同一块。
  • 进程对这块共享内存的读写操作会直接反映到物理内存上,因此其他进程也能立即看到变化。
2.3 为什么高效?
  • 无需数据拷贝:在共享内存机制中,数据直接存储在共享的物理内存中,进程可以直接读写这块内存,而无需像管道或消息队列那样通过内核中转数据。
  • 直接访问:共享内存的访问速度接近进程内部的内存操作,效率极高。
2.4 关键点:物理内存共享

跨进程共享内存的关键在于:操作系统确保多个进程的虚拟地址指向相同的物理内存页面。这通过内核提供的共享内存管理接口(如 System V IPC 或 POSIX 共享内存)实现。


3. Linux 共享内存的两种主要机制

Linux 提供了两种主要的共享内存实现方式:System V 共享内存POSIX 共享内存。下面分别介绍它们的实现和使用方式。

3.1 System V 共享内存

System V 共享内存是较早期的 IPC 机制,广泛用于 Unix 系统。它的主要系统调用包括:

  • shmget:创建或获取一个共享内存段。
  • shmat:将共享内存段附加(映射)到进程的地址空间。
  • shmdt:将共享内存段从进程的地址空间分离。
  • shmctl:控制共享内存段(如删除)。

使用步骤

  1. 创建共享内存:调用 shmget 创建一个共享内存段,返回一个唯一的标识符(shmid)。

    c

    int shmget(key_t key, size_t size, int shmflg);

    • key:一个标识符,用于区分不同的共享内存段(可以通过 ftok 生成)。
    • size:共享内存段的大小(字节)。
    • shmflg:标志位,如 IPC_CREAT(创建新段)或权限设置。
  2. 映射共享内存:调用 shmat 将共享内存映射到进程的虚拟地址空间。

    c

    void *shmat(int shmid, const void *shmaddr, int shmflg);

    • 返回一个指针,指向共享内存的起始地址。
  3. 读写共享内存:进程通过返回的指针直接操作共享内存。
  4. 分离共享内存:使用 shmdt 分离共享内存。

    c

    int shmdt(const void *shmaddr);

  5. 删除共享内存:使用 shmctl 删除共享内存段。

    c

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);

示例代码

c

#include <sys/ipc.h>

#include <sys/shm.h>

#include <stdio.h>

#include <string.h>

int main() {

// 创建共享内存

key_t key = ftok("shmfile", 65);

int shmid = shmget(key, 1024, 0666 | IPC_CREAT);

// 映射共享内存

char *str = (char *)shmat(shmid, (void *)0, 0);

// 写入数据

strcpy(str, "Hello, Shared Memory!");

// 分离共享内存

shmdt(str);

// 删除共享内存(通常由最后一个进程完成)

shmctl(shmid, IPC_RMID, NULL);

return 0;

}

3.2 POSIX 共享内存

POSIX 共享内存是更现代的实现,基于文件映射的方式,使用 mmap 系统调用。它的主要接口包括:

  • shm_open:创建或打开一个共享内存对象。
  • mmap:将共享内存对象映射到进程的地址空间。
  • munmap:解除映射。
  • shm_unlink:删除共享内存对象。

使用步骤

  1. 创建共享内存对象:调用 shm_open 创建一个类似文件的共享内存对象。

    c

    int shm_open(const char *name, int oflag, mode_t mode);

    • name:共享内存的名称,格式如 /shm_name。
    • oflag:标志位,如 O_CREAT(创建)或 O_RDWR(读写)。
    • mode:权限,如 0666。
  2. 设置大小:使用 ftruncate 设置共享内存对象的大小。

    c

    int ftruncate(int fd, off_t length);

  3. 映射共享内存:使用 mmap 将共享内存对象映射到进程地址空间。

    c

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

  4. 读写共享内存:通过返回的指针操作共享内存。
  5. 解除映射和删除:使用 munmap 解除映射,shm_unlink 删除共享内存对象。

示例代码

c

#include <sys/mman.h>

#include <fcntl.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

int main() {

// 创建共享内存对象

int fd = shm_open("/myshm", O_CREAT | O_RDWR, 0666);

ftruncate(fd, 1024); // 设置大小

// 映射共享内存

char *ptr = mmap(0, 1024, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);

// 写入数据

strcpy(ptr, "Hello, POSIX Shared Memory!");

// 解除映射

munmap(ptr, 1024);

// 删除共享内存对象

shm_unlink("/myshm");

close(fd);

return 0;

}


4. 跨进程共享内存的注意事项

虽然共享内存高效,但使用时需要注意以下问题:

4.1 同步问题

共享内存允许多个进程同时读写同一块内存,但没有内置的同步机制。如果多个进程同时写入,可能会导致**数据竞争(race condition)**或数据不一致。因此,通常需要结合其他同步机制,如:

  • 信号量(Semaphore):用于互斥访问或协调读写顺序。
  • 互斥锁(Mutex):在 POSIX 共享内存中可以使用 pthread_mutex。
  • 原子操作:在某些场景下使用原子操作避免锁。

示例(使用信号量同步)

c

#include <sys/sem.h>

union semun {

int val;

struct semid_ds *buf;

unsigned short *array;

};

void sem_wait(int semid) {

struct sembuf sb = {0, -1, 0};

semop(semid, &sb, 1);

}

void sem_signal(int semid) {

struct sembuf sb = {0, 1, 0};

semop(semid, &sb, 1);

}

4.2 内存管理
  • 清理共享内存:System V 共享内存需要显式调用 shmctl 删除,POSIX 共享内存需要调用 shm_unlink,否则可能导致内存泄漏。
  • 权限控制:共享内存的访问权限需要通过 shmget 或 shm_open 的权限参数设置,避免未经授权的访问。
4.3 适用场景
  • 高性能需求:适合需要频繁、大量数据交换的场景,如多媒体处理、数据库缓存等。
  • 复杂同步场景:如果同步需求复杂,建议结合其他 IPC 机制(如信号量或消息队列)。

5. 共享内存的优缺点

优点:
  1. 高效:数据直接在内存中读写,减少了内核态和用户态之间的数据拷贝。
  2. 灵活:进程可以像操作普通内存一样操作共享内存。
  3. 大容量:适合传输大量数据。
缺点:
  1. 同步复杂:需要开发者自行实现同步机制。
  2. 安全性:没有适当的权限控制可能导致数据泄露。
  3. 管理复杂:需要手动管理共享内存的创建、映射和清理。

6. 总结

Linux 共享内存通过将同一块物理内存映射到多个进程的虚拟地址空间,实现了高效的跨进程通信。System V 和 POSIX 共享内存是两种主要实现方式,分别适用于不同场景。共享内存的高效性来自于直接操作物理内存,但需要开发者处理同步和内存管理问题。

http://www.dtcms.com/a/344870.html

相关文章:

  • 前端在WebSocket中加入Token的方法
  • 12-Linux系统用户管理及基础权限
  • 塞尔达传说 王国之泪 PC/手机双端 免安装中文版
  • celery
  • C语言翻译环境作业
  • 大学校园安消一体化平台——多警合一实现智能联动与网格化管理
  • 【链表 - LeetCode】19. 删除链表的倒数第 N 个结点
  • Android.mk 基础
  • Electron 核心 API 全解析:从基础到实战场景
  • 从零开始搭 Linux 环境:VMware 下 CentOS 7 的安装与配置全流程(附图解)
  • openstack的novnc兼容问题
  • 【日常学习】2025-8-20 框架中控件子类实例化设计
  • FPGA学习笔记——简单的IIC读写EEPROM
  • LeetCode 3195.包含所有 1 的最小矩形面积 I:简单题-求长方形四个范围
  • 化工生产场景下设备状态监测与智能润滑预测性维护路径
  • 校园作品互评管理移动端的设计与实现
  • Boost库中boost::random::normal_distribution(正态分布)详解和实战示例
  • 腾讯云EdgeOne安全防护:快速上手,全面抵御Web攻击
  • 如何优雅的监听dom的变化(尺寸)
  • php apache无法接收到Authorization header
  • JDK17 升级避坑指南:技术原理与解决方案详解
  • 【学习记录】structuredClone,URLSearchParams,groupBy
  • 【大语言模型 14】Transformer权重初始化策略:从Xavier到GPT的参数初始化演进之路
  • 网络编程8.22
  • Python面试常考函数
  • 技术分析 剖析一个利用FTP快捷方式与批处理混淆的钓鱼攻击
  • RSS与今日头条技术对比分析
  • Unreal Engine UObject
  • 嵌入式-EXTI的工作原理和按钮实验-Day19
  • 6口千兆图像采集卡:突破多路高清视觉系统的传输瓶颈