C与Python基于mmap实现共享映射文件读写的问题及解决方案
如何用Python向C创建的共享内存映射写入长字符串?
问题概述
你需要实现这样的场景:由C程序创建共享映射文件,Python程序向其中写入长字符串,供C程序读取。但在尝试过程中遇到了两个关键报错:
- 首次尝试时Python抛出
IndexError: mmap assignment must be single-character string,且C程序只能读取到初始字符"1" - 尝试写入两个字符串时又出现
IndexError: mmap slice assignment is wrong size
问题根源
- 第一个错误:你最初的Python代码里用
mm[0] = "01",这违反了mmap的规则——单个索引位置只能赋值单字符字符串,不能直接写入多字符内容。 - 第二个错误:使用
sys.getsizeof()计算字符串大小是错误的,这个函数返回的是Python字符串对象的总内存占用(包含额外的对象开销),而非字符串实际的字节长度。同时,最初的映射文件尺寸太小,也会导致写入时的尺寸不匹配问题。
修正后的可运行代码
在Sam Mason的帮助下,我们得到了可以正常工作的C和Python代码:
C程序(创建共享映射并读取内容)
#include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { int fd = open("hello.txt", O_RDWR | O_CREAT, 0666); if (fd == -1) { perror("unable to open"); return 1; } // 将文件大小设置为4096字节(标准内存页大小,确保有足够空间存储长字符串) if (ftruncate(fd, 4096) < 0) { perror("unable to set length"); return 1; } // 创建共享内存映射,先赋予读写权限用于初始化 char *shared = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (shared == MAP_FAILED) { perror("mmap failed"); close(fd); return 1; } // 调用Python脚本写入内容 system("python3 mappalo.py"); // 读取并打印共享内存中的字符串 printf("C CODE: %s\n", shared); // 释放映射和文件描述符 munmap(shared, 4096); close(fd); return 0; }
Python程序(向共享映射写入长字符串)
import mmap import struct with open('hello.txt', 'r+b') as fd: # 创建对应大小的内存映射 buf = mmap.mmap(fd.fileno(), 4096, access=mmap.ACCESS_DEFAULT) arr = bytes("Hello123;", 'utf-8') arr1 = bytes("Hello412;", 'utf-8') # 用len()获取字节串的实际长度,而非sys.getsizeof() size = len(arr) + len(arr1) # 构造struct格式字符串,比如两个8字节字符串对应"8s8s" types = f"{len(arr)}s{len(arr1)}s" # 打包字符串后批量写入映射区域 buf[:size] = struct.pack(types, arr1, arr) buf.close()
核心改进说明
- 固定映射文件大小:C程序中通过
ftruncate将文件设置为4096字节(标准内存页大小),确保有足够空间存储长字符串,避免写入时超出范围。 - 正确计算字节长度:使用
len()获取字节串的真实长度,避免了sys.getsizeof()带来的对象额外开销导致的尺寸不匹配。 - 批量写入方式:通过
struct.pack将多个字符串打包成字节流,再通过切片赋值写入mmap,避开了单个字符赋值的限制。 - 资源清理:添加
munmap和close操作,正确释放内存映射和文件描述符,防止资源泄漏。
内容的提问来源于stack exchange,提问作者giupardeb
相关产品推荐
相关产品推荐

