通过SHM传输后字符串无法显示的问题排查与解决
解决进程间共享内存传输EdgeList时字符串指针无效的问题
问题根源
你定义的Edge结构体里的from和to是指针类型,这些指针存储的是发送进程虚拟地址空间内的内存地址。由于不同进程的虚拟地址空间完全独立,接收进程拿到这些地址后,要么指向自身进程的无效内存区域,要么直接是野指针,因此读取时会显示(null)。
解决方案
1. 改用固定大小字符数组替代指针(最推荐)
把Edge中的指针替换为固定长度的字符数组,让字符串内容直接嵌入共享内存的结构体中,接收进程可以直接读取。
修改后的类型定义示例:
// 根据实际业务场景调整最大节点名称长度 #define MAX_NODE_NAME_LENGTH 64 // 如果每个EdgeList的最大边数固定,也可以直接嵌入数组 #define MAX_EDGES_PER_LIST 1024 typedef struct { char from[MAX_NODE_NAME_LENGTH]; char to[MAX_NODE_NAME_LENGTH]; } Edge; typedef struct { size_t numEdges; Edge fst[MAX_EDGES_PER_LIST]; } EdgeList; typedef struct { EdgeList buffer[BUFFER_SIZE]; // 其他同步字段(比如读写指针、互斥锁等) } CircularBuffer;
注意:需要提前预估最大节点名称长度和单条EdgeList的最大边数,避免内存溢出。如果无法预估,再考虑其他方案。
2. 用偏移量替代绝对指针(支持动态长度)
如果必须使用动态长度的字符串,不要存储绝对内存指针,而是存储相对于共享内存起始地址的偏移量。接收进程读取时,将偏移量加上共享内存的起始地址(mmap返回的地址),即可得到有效的字符串地址。
修改后的类型定义示例:
typedef struct { // 存储相对于共享内存首地址的偏移量,替代原char*指针 size_t from_offset; size_t to_offset; } Edge; typedef struct { size_t numEdges; // Edge数组相对于共享内存首地址的偏移量 size_t edges_offset; } EdgeList; typedef struct { EdgeList buffer[BUFFER_SIZE]; // 同步字段 + 记录共享内存空闲位置的字段 size_t free_offset; } CircularBuffer;
发送进程写入逻辑:
// shm_ptr是mmap返回的共享内存起始地址 CircularBuffer *shm = (CircularBuffer*)shm_ptr; // 假设当前要写入的buffer槽位是slot EdgeList *current_el = &shm->buffer[slot]; current_el->numEdges = getSolutionNumEdges(); // 分配Edge数组的空间,计算偏移量 current_el->edges_offset = shm->free_offset; Edge *edges = (Edge*)((uint8_t*)shm_ptr + shm->free_offset); shm->free_offset += current_el->numEdges * sizeof(Edge); for (size_t i = 0; i < current_el->numEdges; i++) { const char *from_str = getSolutionEdgeFrom(i); const char *to_str = getSolutionEdgeTo(i); // 写入from字符串到共享内存空闲区域,记录偏移 edges[i].from_offset = shm->free_offset; memcpy((uint8_t*)shm_ptr + shm->free_offset, from_str, strlen(from_str) + 1); shm->free_offset += strlen(from_str) + 1; // 写入to字符串 edges[i].to_offset = shm->free_offset; memcpy((uint8_t*)shm_ptr + shm->free_offset, to_str, strlen(to_str) + 1); shm->free_offset += strlen(to_str) + 1; }
接收进程读取逻辑:
CircularBuffer *shm = (CircularBuffer*)shm_ptr; EdgeList *current_el = &shm->buffer[slot]; Edge *edges = (Edge*)((uint8_t*)shm_ptr + current_el->edges_offset); for (size_t i = 0; i < current_el->numEdges; i++) { // 通过偏移量计算有效地址 char *from = (char*)((uint8_t*)shm_ptr + edges[i].from_offset); char *to = (char*)((uint8_t*)shm_ptr + edges[i].to_offset); // 使用from和to字符串 }
3. 序列化/反序列化方案
将EdgeList序列化为二进制字节流或结构化格式(如自定义二进制协议、JSON等),写入共享内存后,接收进程再将字节流反序列化为EdgeList结构体。这种方案适合复杂数据结构,但需要额外实现序列化逻辑,性能略低于前两种方案。
内容的提问来源于stack exchange,提问作者sueszli
相关产品推荐
相关产品推荐

