Linux中使用/dev/shm共享内存对象的IPC机制延迟问题咨询
多核心进程共享内存可见性问题的解决方案
你的问题本质不是内核刷写共享内存的延迟,而是CPU缓存一致性与内存可见性问题:每个CPU核心拥有独立的L1/L2缓存,当process1写入共享内存时,数据会先存在当前核心的缓存中,若未同步到其他核心的缓存,process2读取时就会拿到旧值。msync仅用于将内存映射的数据刷写到磁盘(/dev/shm是内存文件系统,无实际磁盘写入),因此无法解决缓存同步问题。
以下是几种可靠的解决方法:
1. 使用原子操作(推荐,最轻量)
利用C标准库的stdatomic.h或编译器内置的原子操作函数,确保写操作的内存可见性,同时避免数据竞争。原子操作会自动插入内存屏障,强制缓存同步。
Process1 代码片段
#include <stdatomic.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> int main() { int fd = shm_open("/transfer_info", O_RDWR | O_CREAT, 0666); ftruncate(fd, sizeof(atomic_char)); atomic_char *shared_data = mmap(NULL, sizeof(atomic_char), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 写入'1',release序保证写操作对其他核心可见 atomic_store_explicit(shared_data, '1', memory_order_release); sleep(1); // 写入'0' atomic_store_explicit(shared_data, '0', memory_order_release); munmap(shared_data, sizeof(atomic_char)); close(fd); return 0; }
Process2 代码片段
#include <stdatomic.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <stdio.h> int main() { int fd = shm_open("/transfer_info", O_RDWR, 0666); atomic_char *shared_data = mmap(NULL, sizeof(atomic_char), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); char val; // 读取直到拿到'1',acquire序保证读取到最新值 do { val = atomic_load_explicit(shared_data, memory_order_acquire); } while (val != '1'); printf("读到值: '1'\n"); // 读取直到拿到'0' do { val = atomic_load_explicit(shared_data, memory_order_acquire); } while (val != '0'); printf("读到值: '0'\n"); munmap(shared_data, sizeof(atomic_char)); close(fd); shm_unlink("/transfer_info"); return 0; }
2. 手动插入内存屏障
针对不同CPU平台插入对应的内存屏障指令,强制缓存同步。这种方式需要注意平台兼容性(如x86用mfence,ARM用dsb)。
Process1 写后加屏障
shared_data[0] = '1'; // x86平台内存屏障,确保写操作同步到所有核心缓存 asm volatile("mfence" ::: "memory");
Process2 读前加屏障
// x86平台读屏障,确保读取最新的缓存数据 asm volatile("lfence" ::: "memory"); char val = shared_data[0];
3. 使用跨进程互斥锁
通过POSIX互斥锁保护共享内存的读写操作,互斥锁的加锁/解锁操作会自动触发内存屏障,保证缓存同步。适合更复杂的共享数据场景。
Process1 代码片段
#include <pthread.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> typedef struct { pthread_mutex_t mutex; char data; } SharedData; int main() { int fd = shm_open("/transfer_info", O_RDWR | O_CREAT, 0666); ftruncate(fd, sizeof(SharedData)); SharedData *shared = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 初始化跨进程互斥锁 pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&shared->mutex, &attr); // 写'1' pthread_mutex_lock(&shared->mutex); shared->data = '1'; pthread_mutex_unlock(&shared->mutex); sleep(1); // 写'0' pthread_mutex_lock(&shared->mutex); shared->data = '0'; pthread_mutex_unlock(&shared->mutex); munmap(shared, sizeof(SharedData)); close(fd); return 0; }
Process2 代码片段
#include <pthread.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <stdio.h> typedef struct { pthread_mutex_t mutex; char data; } SharedData; int main() { int fd = shm_open("/transfer_info", O_RDWR, 0666); SharedData *shared = mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); char val; // 读'1' do { pthread_mutex_lock(&shared->mutex); val = shared->data; pthread_mutex_unlock(&shared->mutex); } while (val != '1'); printf("读到值: '1'\n"); // 读'0' do { pthread_mutex_lock(&shared->mutex); val = shared->data; pthread_mutex_unlock(&shared->mutex); } while (val != '0'); printf("读到值: '0'\n"); pthread_mutex_destroy(&shared->mutex); munmap(shared, sizeof(SharedData)); close(fd); shm_unlink("/transfer_info"); return 0; }
内容的提问来源于stack exchange,提问作者Pavankumar S V
相关产品推荐
相关产品推荐

