Linux下C语言共享内存仅在系统调用后更新的问题咨询
共享内存更新无法同步的问题解决
问题描述
编写了两个小型C程序:Server通过shm_open创建共享内存并循环写入数据;Client读取该共享内存并显示当前值。但Client无法看到Server的更新,除非Server调用sleep或printf等系统调用。仅当Server.c中取消sleep(1)注释时程序才能正常工作。
Server.c
#include <sys/mman.h> #include <fcntl.h> int main (int argc, char *argv[]){ int fd = shm_open("/SHM_TEST", O_RDWR | O_CREAT, S_IRWXU); ftruncate(fd, 4096); unsigned char *ptr = mmap(0,4096,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,fd,0); while(1){ for(unsigned short int i=0;i<256;i++){ *ptr = i; //sleep(1); } } }
Client.c
#include <sys/mman.h> #include <fcntl.h> int main (int argc, char *argv[]){ int fd = shm_open("/SHM_TEST", O_RDWR, S_IRWXU); unsigned char *ptr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); int i = 0; while(1){ printf("%d--%d\n", *ptr, i); i++; } }
原因分析
你的猜测正确,这是CPU缓存一致性机制导致的问题,共享内存确实映射到了同一物理内存。CPU为提升性能,会把频繁访问的内存数据加载到本地高速缓存中,Server的写入操作仅修改了自身CPU缓存里的数据,没有及时同步到主存,导致Client读取的仍是旧的主存数据。而sleep、printf这类系统调用会触发内核态切换,此时CPU会自动刷新缓存到主存,所以取消sleep注释后Client能读到更新。
解决方法
无需依赖系统调用,通过内存屏障即可强制缓存同步:
在Server的写入操作后添加GCC内置的内存屏障函数__sync_synchronize(),它会强制CPU将缓存中的数据写回主存,并使其他CPU的对应缓存失效,确保Client能读取到最新值。修改后的Server循环代码如下:
while(1){ for(unsigned short int i=0;i<256;i++){ *ptr = i; __sync_synchronize(); // 触发缓存同步,无需系统调用 } }
另外也可以将共享内存标记为非缓存区域,但这会大幅降低内存访问性能,不推荐使用。
内容的提问来源于stack exchange,提问作者bearIO
相关产品推荐
相关产品推荐

