Linux下跨进程共享内存:能否用P1虚拟地址让P2写入?
方案不可行,原因及正确实现方式
你的方案完全不可行,核心原因是:Linux下每个进程拥有独立的虚拟地址空间,P1的虚拟地址仅在P1的地址空间内有效,在P2中要么是未映射的无效地址(触发段错误SIGSEGV),要么指向P2地址空间中完全无关的物理内存区域,根本无法写入到P1创建的共享内存缓冲区里。
正确的跨进程共享内存实现方式
在Linux下,跨进程共享内存需要依赖内核提供的共享内存机制,让两个进程将同一块物理内存映射到各自的虚拟地址空间,常用的两种方式如下:
方式一:POSIX有名共享内存(推荐)
P1 步骤:
- 调用
shm_open创建一个有名共享内存对象,例如:int shm_fd = shm_open("/my_1mb_shm", O_CREAT | O_RDWR, 0666); - 用
ftruncate设置共享内存大小为1MB:ftruncate(shm_fd, 1024 * 1024); - 调用
mmap将共享内存映射到P1的虚拟地址空间:void *buf = mmap(NULL, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - 保持P1运行,不要关闭
shm_fd或解除映射(直到不需要共享内存为止)。
P2 步骤:
- 调用
shm_open打开同一个有名共享内存对象:int shm_fd = shm_open("/my_1mb_shm", O_RDWR, 0666); - 同样调用
mmap将共享内存映射到P2的虚拟地址空间(这个地址和P1的虚拟地址大概率不同,但指向同一块物理内存):void *buf = mmap(NULL, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - 向
buf指向的地址写入数据,完成后解除映射并关闭文件描述符:munmap(buf, 1024 * 1024); close(shm_fd); - 终止P2,此时P1可以从自己的
buf地址读取到P2写入的数据。
方式二:System V共享内存
P1 步骤:
- 调用
shmget创建共享内存段,指定key、大小1MB和权限:key_t key = ftok("/some_existing_file", 'R'); // 用现有文件生成唯一key int shm_id = shmget(key, 1024 * 1024, IPC_CREAT | 0666); - 调用
shmat将共享内存段映射到P1的虚拟地址空间:void *buf = shmat(shm_id, NULL, 0); - 保持P1运行。
P2 步骤:
- 用同一个key调用
shmget获取共享内存段:key_t key = ftok("/some_existing_file", 'R'); int shm_id = shmget(key, 1024 * 1024, 0666); - 调用
shmat映射到P2的虚拟地址空间:void *buf = shmat(shm_id, NULL, 0); - 写入数据后,调用
shmdt解除映射:shmdt(buf); - 终止P2,P1即可读取数据。
关键注意点
- 无论哪种方式,两个进程都必须通过内核提供的接口来关联同一块物理内存,绝对不能直接使用其他进程的虚拟地址。
- 使用POSIX共享内存时,若不再需要共享内存,要调用
shm_unlink删除有名对象,避免系统资源残留。
内容的提问来源于stack exchange,提问作者Mobi Zaman
相关产品推荐
相关产品推荐

