修改共享内存中结构体成员值时程序停滞的技术求助
问题:共享内存中结构体字符串字段操作异常
我用共享内存存储一个结构体数组,每个结构体对应一个游戏房间(lobby)的信息。每个房间由fork创建的独立子进程负责,子进程会把自身房间的数据写入数组,父进程需要查看所有房间的代码。
共享内存初始化代码
int fd = shm_open("tabLobby", O_CREAT | O_RDWR, S_IRWXU); // Set the size of the shared memory object int pageSize = sysconf(_SC_PAGE_SIZE); CHECK(ftruncate(fd, pageSize), "__ftruncate__"); // Map the tabEtats object into the virtual address space of the calling process tabLobby = mmap(0, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
进程创建与数据获取代码
int pidLobby; tabLobby[nbLobby].pidLobby = 0; CHECK(pidLobby = fork(), "fork()"); if(pidLobby == 0) { // Child serveurLobby(nbLobby); exit(EXIT_SUCCESS); } else { // Father while(tabLobby[nbLobby].pidLobby == 0) { sleep(1); } // Show code and port printf(GREEN "Création du Lobby %s (Port %d)\n" RESET, tabLobby[nbLobby].code, tabLobby[nbLobby].port); // Writing response data send_t sendData; sendData.args[0] = tabLobby[nbLobby].ip; sendData.args[1] = tabLobby[nbLobby].code; char* portChar = malloc(sizeof(char) * 5); sprintf(portChar, "%d", tabLobby[nbLobby].port); sendData.args[2] = portChar; }
子进程处理代码
void serveurLobby(int idLobby) { // Emplacement du lobby dans le tableau tabLobby[idLobby].ip = ip; tabLobby[idLobby].port = port; char* code = malloc(sizeof(char) * 6); // This functions generates a random code and puts it into code generateLobbyCode(code); strcpy(tabLobby[idLobby].code, code); printf("Lobby code : %s\n", tabLobby[idLobby].code); tabLobby[idLobby].pidLobby = getpid(); }
异常现象
- 直接执行
tabLobby[idLobby].code = "TEST"时,程序正常运行 - 执行
tabLobby[idLobby].code[0] = 'a'、strcpy/strdup等修改操作时,程序无报错但停滞 - 用
tabLobby[idLobby].code = code替代字符串拷贝函数,函数结束后数据丢失
解决方法
核心问题是你的结构体中code字段定义成了char*指针,而非固定大小的字符数组,这是共享内存场景下的典型错误:
- 执行
tabLobby[idLobby].code = "TEST"时,指针指向的是进程地址空间中的常量字符串,父子进程地址空间可能巧合映射了同一段常量区,所以能读到,但这是不可靠的行为。 - 用
strcpy或直接修改code[0]时,指针指向的要么是非法内存(导致程序停滞),要么是子进程私有堆内存(父进程无法访问)。 tabLobby[idLobby].code = code是把子程序malloc的堆内存地址赋值给指针,该地址仅在子进程有效,父进程访问时属于无效内存,数据自然丢失。
修复步骤:
修改结构体定义:把
char* code改成固定大小的字符数组,比如char code[6];(匹配你生成的5位代码加结束符的需求)。确保结构体所有字段都存储在共享内存中,而非指向外部内存区域。注意:如果
ip字段也是char*,同样要改成固定大小数组,比如char ip[INET_ADDRSTRLEN];,否则会遇到相同问题。调整子进程代码:直接使用共享内存中的数组存储代码,无需额外
malloc:void serveurLobby(int idLobby) { tabLobby[idLobby].ip = ip; // 若ip是指针需替换为数组拷贝,比如strcpy(tabLobby[idLobby].ip, ip); tabLobby[idLobby].port = port; // 直接将生成的代码写入共享内存数组 generateLobbyCode(tabLobby[idLobby].code); printf("Lobby code : %s\n", tabLobby[idLobby].code); tabLobby[idLobby].pidLobby = getpid(); }父进程直接读取数组:无需担心指针有效性问题,直接访问
tabLobby[nbLobby].code即可。
额外注意事项:
- 共享内存操作需保证原子性,当前用
pidLobby作为同步标志可行,若有复杂并发操作,建议配合信号量或互斥锁避免数据竞争。 - 确保
ftruncate设置的共享内存大小足够容纳整个结构体数组,避免越界访问。
内容的提问来源于stack exchange,提问作者Namu
相关产品推荐
相关产品推荐

