C编程:共享内存中map意外自行变更问题排查求助
int** map会莫名变? 老哥,你这问题我一眼就瞅到核心坑了——共享内存里直接存int**类型绝对是踩了经典的指针陷阱! 下面给你拆解几个必然会出问题的点:
指针是“进程专属”的虚拟地址:
int** map说白了就是个指向指针数组的指针,这些指针指向的都是你当前进程自己虚拟地址空间里的内存块。共享内存只会把这个指针的数值(也就是那个虚拟地址)存进去,但这个地址只在你当前进程的这一刻有效——要是后续进程分配/释放了内存,虚拟地址布局一变,原来的指针指向的区域要么被覆盖,要么变成无效的野指针,看起来就像是map自己偷偷变了。你存错东西了! 共享内存要存的是棋盘的实际数据,不是指向数据的指针。比如你的棋盘是固定大小的,就定义成
int map[10][10]这种连续的二维数组,直接把整个数组拷贝进共享内存;要是大小动态,就先算好总数据量(比如行数*列数*sizeof(int)),申请对应大小的共享内存,然后用一维数组模拟二维访问(比如map[row*列数 + col]),全程别用指针的指针。缓存同步没做? 就算你存对了数据,要是写完共享内存后没强制同步缓存,CPU可能还把数据存在自己的缓存里没刷回共享内存,后续读的时候拿到的就是旧数据或者错误值,看起来也像是
map变了。记得写完后调用msync(shmaddr, 内存大小, MS_SYNC),再配合信号量的P/V操作把读写操作都保护起来。有没有越界写? 检查下你申请共享内存的大小是不是算小了,要是写入的时候越界了,刚好覆盖到
map指针所在的内存区域,那它的值肯定会被意外改掉。
快速改法参考
- 把
int** map换成连续的二维数组,比如typedef int board_t[BOARD_ROWS][BOARD_COLS];,然后把整个board_t对象拷贝进共享内存; - 动态大小的话,直接在共享内存里存一维数组,用
row*COLS + col的方式访问二维位置; - 所有读写共享内存的代码都用信号量包起来,写完必须调用
msync; - 核对共享内存的申请大小,确保比实际需要存的数据量至少大一点,别卡得刚刚好。
内容的提问来源于stack exchange,提问作者bibi k.

