C语言semaphore与mutex的区别及多共享数据线程锁选型问题
信号量与互斥锁的核心差异及使用场景
1. sem_wait/sem_post 与 pthread_mutex_lock/pthread_mutex_unlock 作用不一致,核心区别如下:
- 功能定位不同:互斥锁仅用于实现临界资源的互斥访问,同一时间最多只能有1个线程持有锁;信号量是通用的同步计数器,初始值可设置为≥1的整数,支持同时允许多个线程进入临界区。
- 所有权规则不同:互斥锁严格遵循「谁加锁谁解锁」的规则,只有持有锁的线程才能执行解锁操作;信号量没有所有权限制,任意线程都可以调用
sem_post将计数加1,哪怕它没有调用过sem_wait。哪怕是初始值为1的二值信号量,也和互斥锁不完全等价,误用信号量很容易打破临界区的互斥性。 - 初始化规则:你提到的「pthread_mutex无需初始化」是认知误区,pthread_mutex也需要初始化,要么静态初始化为
PTHREAD_MUTEX_INITIALIZER,要么动态调用pthread_mutex_init完成初始化,只是静态初始化写法更简洁,看起来像无需初始化而已。
2. 二者适配的使用场景
- 互斥锁适用场景:纯互斥访问场景,即多个线程争抢同一个临界资源,同一时间只允许一个线程读写(比如修改全局变量、读写单个链表)。
- 信号量适用场景:
- 并发数控制场景:比如最多允许3个线程同时访问资源池,可将信号量初始值设为3。
- 线程间事件通知场景:比如生产者-消费模型中,生产者生产完数据调用
sem_post通知消费者,消费者调用sem_wait等待数据,这类同步场景仅用互斥锁无法实现,需要额外配合条件变量才能达到相同效果。
多共享资源的加锁方案合理性分析
你定义的两个独立共享链表:
linkedlist sharedtype1; linkedlist sharedtype2;
1. 分别用mutex1和mutex2独立加锁的方案是合理的
这种做法属于锁粒度拆分,可以有效提升并发效率:当线程A持有mutex1读写sharedtype1时,线程B可以正常持有mutex2读写sharedtype2,二者不会互相阻塞,性能远高于用同一把锁保护两个链表的方案。
2. 其他场景的选型参考
- 若两个链表需要联动操作(比如从
sharedtype1删除节点、添加到sharedtype2的操作要求原子性,不允许其他线程读到中间状态),则需要用同一把锁同时保护两个链表。 - 若链表作为任务队列使用,需要实现生产消费的流量控制(比如队列最多存10个任务,满时生产者阻塞,空时消费者阻塞),才需要用信号量配合互斥锁实现,纯互斥读写链表的场景不需要使用信号量。
内容的提问来源于stack exchange,提问作者randomNameGenerator
相关产品推荐
相关产品推荐

