多进程多线程共享内存环境下pthread读写锁异常问题
跨进程读写锁异常问题分析
问题背景
在多进程、多线程环境中,将pthread_rwlock_t读写锁存储在共享内存中供所有进程访问,出现了锁释放后等待者无法及时获取锁的异常。
初始锁初始化代码
rw_lock = (pthread_rwlock_t *) ShmemAlloc(sizeof(pthread_rwlock_t)); if(pthread_rwlock_init(rw_lock, NULL)) { // Handle error }
Process A 获取读锁逻辑
lockStatus = pthread_rwlock_tryrdlock(rw_lock); switch(lockStatus) { case 0: break; case EBUSY: for(int i = 0; i < 10000; i++) { pg_usleep(100); lockStatus = pthread_rwlock_tryrdlock(rw_lock); if(!lockStatus) { break; } } if(!lockStatus) { break; } case EINVAL: default: printf(ERROR, "COULD NOT GET SHARED LOCK"); break; }
Process B 获取写锁逻辑
if(pthread_rwlock_wrlock(rw_lock)) { printf(ERROR, "COULD NOT GET EXCLUSIVE LOCK"); }
异常现象
预期Process A释放读锁后,Process B能立即获取写锁,但实际观察到:有时Process B需等待5-30秒才能获取锁,有时完全无法获取。
修复方案
修改初始化代码,添加PTHREAD_PROCESS_SHARED属性后,问题解决:
rw_lock = (pthread_rwlock_t *)ShmemAlloc(sizeof(pthread_rwlock_t)); pthread_rwlockattr_t attr; pthread_rwlockattr_init(&attr); pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); if(pthread_rwlock_init(rw_lock, &attr)) { pthread_rwlockattr_destroy(&attr); // Handle error }
疑问
- 未设置
PTHREAD_PROCESS_SHARED属性时,Process B为何能感知到Process A持有共享锁?是否依赖某种内部机制等待? - 为何设置该属性后Process B能及时感知锁释放,而初始场景不行?pthread库如何跨进程通知锁释放?
解答
问题1:未设置PTHREAD_PROCESS_SHARED时的锁感知逻辑
当不指定该属性时,pthread读写锁的默认属性是PTHREAD_PROCESS_PRIVATE——这个属性的设计意图是锁仅对同一进程内的线程可见。但由于锁存储在共享内存中,Process B能直接读取到锁结构的内存状态(比如记录读锁持有者数量、写锁是否被持有的标记字段),这是内存共享带来的“意外”可见性,而非pthread库的跨进程支持逻辑。
此时Process B的等待没有有效唤醒机制:pthread库不会为私有属性的锁维护跨进程的等待队列,Process B的wrlock调用只能依赖系统内核的低效调度轮询,甚至可能陷入错误的等待状态,这就是你看到延迟或无法获取锁的原因。
问题2:PTHREAD_PROCESS_SHARED的作用与跨进程通知机制
设置PTHREAD_PROCESS_SHARED属性后,pthread库会将读写锁配置为支持跨进程同步的模式:
- 锁内部会使用内核级的跨进程同步原语,比如内核维护的信号量、条件变量,这些对象所有进程都能通过共享内存关联访问。
- 当Process A释放读锁时,pthread库会主动触发内核的唤醒逻辑:直接通知在等待队列中的Process B,而非让其被动等待系统调度。
具体来说,进程共享模式下的读写锁内部包含:
- 存储在共享内存中的状态字段,记录锁的持有情况。
- 内核维护的等待队列:所有等待该锁的进程/线程都会被加入队列,锁释放时内核会遍历队列,唤醒符合条件的等待者(通常写锁优先级高于读锁)。
这种主动唤醒的机制,让Process B能在锁释放后立即感知并获取锁。
内容的提问来源于stack exchange,提问作者Joan Jeremiah J
相关产品推荐
相关产品推荐

