线程同步:为什么条件变量要和互斥锁一起使用,而信号量不用?

条件变量需要搭配互斥锁使用的原因

从调用pthread_cond_wait()到真正被挂起进入等待队列需要时间)

为了应对线程1在调用pthread_cond_wait()但线程1还没有进入wait cond的状态的时候()此时如果线程2调用了 cond_singal 的情况,那么这个cond_singal就丢失了,有可能造成线程1无限等待。

加了锁(wait与singal用同一把锁)的情况是,线程2必须等到 mutex 被释放(也就是 pthread_cod_wait() 真正进入wait_cond状态并释放锁此时线程2才能获得锁并调用cond_singal,这样就会保证线程2顺利进入wait状态而且线程2的cond_singal信号不会丢失;

mutex+条件变量错误使用

mutex+条件变量的错误示例:(还是有可能造成信号丢失)
在这里插入图片描述

mutex需配合pthread_cond_wait()函数正确使用;

在这里插入图片描述

pthread_cond_wait(cond,mutex);保证了该线程先进入cond_wait状态,再释放锁是一个线程安全的原子操作;

虚假唤醒

这里判断条件设置成while()的原因是因为Linux多线程中存在虚假唤醒(由于某种原因某个cond_singal有可能唤醒了多个wait的进程),则用while()会反复判断当前条件,就算被bug误唤醒,但是条件成立还是会进入wait状态;

在这里插入图片描述

模拟虚假唤醒的情况(多生产多消费模型):

  1. 假设初始队列为空, 此时thread2阻塞在wait中:
  2. thread3生产一个, 此时队列不为空, thread3发送signal通知, 并且unlock;
  3. thead2的wait虽然收到通知了, 但是thread2和thread1还在竞争lock(线程2,1都是消费者,signal后都从wait队列进入锁竞争队列)
  4. 假设thread1先抢到了lock, 消费了, 此时队列为空, 然后unlock;
  5. 此时假设thread2抢到了lock, wait也就终于返回了, 但是有while循环, 再次判断队列是否为空, 发现仍然为空(已经被thread1偷过去消费掉了), 所以并不能退出while循环, 所以再次wait, 这就正常了

信号量不需要配合mutex使用的原因

信号量的本质是一个计数器

在这里插入图片描述

借用环形生产消费队列模型举例:

sem_t sem_data;//生产的产品数量;

sem_t sem_space;//剩余空间数量;

等待信号量

功能:等待信号量,会将信号量的值减1

int sem_wait(sem_t *sem); //P()操作

发布信号量

功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。

int sem_post(sem_t *sem);//V()操作

当需要取走产品时,会先看看sem_data里-1以后会不会<0,如果其<0则wait,否则继续执行;
在这里插入图片描述

取走成功以后会给sem_post(space_sem),相当于剩余空间+1;

同时,当生产产品的时候会先检测有没有剩余空间,如果space_sem-1<0(它==0)则会进入wait状态,等待某次去走后space_sem+1,再继续生产;
在这里插入图片描述

所以信号量是利用多线程改变计数器数量动态实现同步的,同时P / V操作是原子操作,因此不需要搭配互斥锁使用;

总结

条件变量+互斥锁 和 信号量 都是线程同步的方法,适用于不同的场景;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏天乐大帅哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值