Linux:线程同步&条件变量(单生成者与消费者分析)

条件变量不能进行单独的线程同步
因为不管是条件变量还是锁,都是在阻塞线程,阻塞结束放行
条件变量可以给多个线程放行,多线程访问临界区就会有问题

  • 生产者与生产者之间的关系:
    互斥,防止将数据放进同一队列中
  • 消费者与消费者之间的关系:
    互斥
  • 生产者与消费者之间的关系:
    同步+互斥
    满了不能放,空了不能取
    互斥体现:放的时候也不能取

同步概念:

线程以特定顺序访问临界资源

单个生成者消费者同步例子:吃面问题

问题描述:

  • val为碗,有面值=1,没有值=0;
  • eat线程代表顾客吃面,对val进行- -;make代表厨师做面,对val进行++;
  • 正常的屏幕输入输出是0101,也就是顾客吃完厨师才能做面;
  • 一个线程不能在执行临界区途中,另一个线程也访问临界区;

使用条件变量

一个线程互斥的访问某个变量,会发现

  • 本质是一个PCB等待队列,该等待队列中存放线程或者进程的PCB
  • 进入PCB等待队列的线程,只有等待被唤醒才能使用CPU执行后续代码,自身再等待队列中是无法使用CPU的;
  • 条件变量必须和互斥锁搭配使用
    因为线程1调用wait函数,并进入wait状态是需要时间的,如果在这个过程中,线程2进行唤醒操作已经完成,那么线程1会一直陷入wait状态。
    加锁后,线程2必须等到锁释放才能去唤醒。

通过生产者与消费者理解条件变量


现有一个PCB等待队列

  • eat线程发现val=0,就调用条件变量的等待接口把自己放入PCB等待队列中
  • make线程执行val=++,就会通知PCB等待队列;
  • eat线程就会从PCB等待队列中移除,再执行eat线程;
  • val- -,eat线程就会通知make进行

对于make线程也一样

  • make线程判断val>=1,就会让自己的线程进入等待队列

同步是让线程产生一定的顺序,之前为什么是所有线程竞争一把锁
以前由系统唤醒线程,现在通过条件变量由程序员自己唤醒线程
条件变量要和互斥锁一起使用
所用接口
在这里插入图片描述在这里插入图片描述
线程被唤醒后,pthread_wait函数会自动帮助线程抢锁

加while的原因是防止被伪唤醒,唤醒后要竞争锁,而后续代码直接就往队列里塞数据了(如果队列依然满着就出现问题了)

在这里插入图片描述

结论:所有线程同步(你说完我再做就是同步)问题就需要使用条件变量解决
36行的加锁操作通常放在唤醒函数后,因为加锁操作只保证临界资源的原子操作,不过放在唤醒函数后也可以

wait函数参数有互斥锁 && wait的内部逻辑

因为在该函数内部,要先解锁,然后其它线程就可以进行加锁

  • eat线程发现碗里没有面,则进入队列中,调用wait函数后将锁释放
  • make线程拿到锁,就可以访问碗生产临界资源,并唤醒eat
  • eat一旦被唤醒,进行抢锁;
    抢到了wait真正返回,回到用户空间执行代码
    没抢到wait就阻塞在wait函数内部的抢锁逻辑中,直到抢锁成功才返回

这个锁是第13行加的那把锁

线程是先进入队列再解锁;被唤醒后有一个加锁逻辑,加锁完成后函数才会结束;

假设:线程是先解锁再进入队列,且eat运行速度慢,make快

  • 如果eat线程调用wait,先解锁再进入队列,make线程直接加锁
  • make运行快eat运行慢; 可能会导致eat未进入等待队列时,make就以及生成了面,并且通知了一个空的等待队列;
  • 此时eat在make通知过后才慢悠悠的进入队列,eat就会一直去等待make通知,这就出现了问题

多生产多消费产生的问题

假设有4个顾客因为没有饭而陷入阻塞
当厨师唤醒时,一下唤醒了3个
三个顾客被唤醒后需要竞争加锁(只有一个会成功)
1号加锁成功后,23号阻塞在锁上,而不是在cond上
在这里插入图片描述
使用while和两个条件变量的原因:
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值