You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:01:45