POSIX系统进程间共享内存访问代码正确性及编译优化影响问询
问题描述
存在若干进程通过共享内存实现同步,共享内存中的结构体定义如下:
struct Shm { pthread_mutex_t mutex; int a; bool b; double d; };
每个进程会通过mmap()映射该共享内存,并将成员地址保存到本地变量以供后续访问:
// save members to local variables void init() { void *ptr = mmap(nullptr, sizeof(Shm), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); auto shm = (Shm *)ptr; m_mutex = &shm->mutex; m_a = &shm->a; m_b = &shm->b; m_d = &shm->d; } // access shared memory with local variables void print() { pthread_mutex_lock(m_mutex); std::cout << m_a << ", " << m_b << ", " << m_d << std::endl; *m_a = *m_a + 1; *m_b = !(*m_b); *m_d = *m_d / 2.0f; }
请问上述访问共享内存的代码是否正确?编译器是否会进行优化或缓存本地变量,进而导致读写错误?根据Linux的man mmap说明,MAP_SHARED会共享该映射,对映射的更新对其他映射同一区域的进程可见。
回答
1. 代码存在明显的输出错误
print()函数里的输出语句是错误的:std::cout << m_a << ", " << m_b << ", " << m_d << std::endl;输出的是共享内存成员的指针地址,而非成员的实际值。正确写法应该是输出解引用后的变量:
std::cout << *m_a << ", " << *m_b << ", " << *m_d << std::endl;
2. 编译器优化会引发读写错误
虽然MAP_SHARED保证了内核层面的内存可见性(修改会同步到物理内存,其他进程能读取到),但C/C++编译器不知道这些本地指针指向共享内存,会对普通内存指针做如下优化:
- 将
*m_a这类变量的值缓存到寄存器,后续读写直接操作寄存器,而非重新从物理内存读取,导致看不到其他进程的修改; - 延迟将修改写入物理内存,其他进程无法及时获取当前进程的更新。
解决方法是用volatile修饰这些指针变量,告诉编译器每次必须直接读写内存,禁止缓存优化。示例定义如下:
volatile pthread_mutex_t* m_mutex; volatile int* m_a; volatile bool* m_b; volatile double* m_d;
3. 跨进程互斥锁的初始化存在隐患
代码未体现pthread_mutex_t mutex的初始化方式,这是跨进程同步的核心问题:
- 静态初始化必须使用
PTHREAD_MUTEX_INITIALIZER; - 动态初始化时,调用
pthread_mutex_init()必须指定PTHREAD_PROCESS_SHARED属性,否则互斥锁仅能在单个进程内生效,其他进程无法正确锁定/解锁,同步逻辑完全失效。
动态初始化的正确写法示例:
pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&shm->mutex, &attr); pthread_mutexattr_destroy(&attr);
内容的提问来源于stack exchange,提问作者sfzhang
相关产品推荐
相关产品推荐

