多线程并行之美

线程基础

进程和线程

进程是计算机操作系统中任务调度的基本单位,他拥有自己独立的地址空间和系统资源,并不与其它进程共享。
线程是依赖于进程存在的计算机最小调度单位,他们共享进程的地址空间和系统资源,单个进程的线程之间会通过共享资源进行交互
每一个进程至少有一个线程,即主线程,和0到多个工作线程

只有一个收银队列

•我们从超市收银开始说起
•最初的时候,我们的超市只有一个收银通道和一个收银员
•每个顾客在这收银通道排队,他们需要清点自己购买的商品并计算价钱,然后付费

多个收银队列一个收银员

•由于每个顾客清点自己购买的物品都需要一定的时间,后面的顾客就不耐烦了,他们想超市老板投诉说结账太慢了,能不能快一点
•超市老板灵机一动,没问题,我给你们再开辟两条结账通道出来。不过为了成本考虑,我还是只雇用一个收银员吧。
•于是这一个收银员开始辛苦的在每一个通道里分别给排队的用户结账。结账的速度看起来好像快了
•实际上每个用户由于要和收银员核对物品,加上收银员需要在各个队伍之前来回穿梭,客户等待的时间更长了。
•客户再次向老板投诉

多个收银队列多个收银员

•老板想了想,还是再多雇两个收银员吧
•这下结账速度真的快了起来
•老板开始高兴地躺在那里数钱了

新的问题来了

•老板突然想知道每天的实时营业额
•聪明的老板说,你们每个收银员收完一笔钱,都在那个黑板上给我记一下最新的汇总数
•刚开始这个数更新的很好
•突然老板发现这个数从一个大数变成了一个小一点的数。
•这是怎么回事?这是绝不能容忍的事情

•原来收银员A和收银员B同时收了一笔款,他们分别根据之前的汇总数计算除了自己的汇总数
•收银员A更新了自己的汇总数
•收银员B然后也更新了自己的汇总数
•于是收银员A的交易记录没有被正确的统计了
•这可怎么办呢?

这个问题难不倒我

•聪明的超市老板怎么会被这个问题难住呢?
•老板做出了规定,每个人准备去更新自己的数据的时候,一定要先把黑板挡起来不让别人看见,自己更新完了才能把黑板显示出来
•完美解决

线程的进化

单任务时代

•在最初的操作系统中,计算机一次只能执行一个任务,当这个任务结束后才能够执行下一个任务
•由于不同的任务需要处理逻辑的差异导致任务处理过程中需要的计算机系统资源注定不会是相同的
•这就意味着,执行一个任务的时候,总有一些资源是处于闲置状态的。那些伟大的计算机科学家怎么能够容忍宝贵的计算资源被浪费呢?
•于是单任务时代结束了
•计算机科学家们决定进化到多任务时代

多任务时代

•计算机科学家们将计算机进化到了多任务时代,他们终于可以一边听着CD,一边写代码了,啊,不,是计算机终于可以同时执行多个任务了
•当然,这个多个任务还不是真正的同时执行多个任务了。这其实就是一次执行一个任务很小一段时间,然后又执行另外一个任务很小一段时间,多个任务轮流获得执行的时间来真正完成。于是当这个执行时间对于用户感知度不明显的时候,用户就感觉这些任务真的是在同时运行了。
•这个执行时间后来就叫做CPU执行时间片,现代操作系统的基本实现大都是基于这个原理的

单线程时代

•在最初的多任务操作系统中,每一个任务里的子任务都会像超市收银队列那样一个个的排着队等待处理
•伟大(ai zhe teng)的科学家们想着既然能够让多任务可以使用CPU时间片执行原则,为什么不可以让任务也享受这一个原则呢?

多线程时代

•说干就干,计算机科学家们将计算机体系正式升级到了多任务多线程时代
•单个任务也可以根据需要告诉系统安排分配给自己的CPU时间片区执行自己多个的线程
•但是,请注意一点,系统是一个很懒很懒的家伙,它可能不会按照你想象的执行顺序去执行你的线程。就如同右边的收银员可能总是按照固定的顺序在三个队列之间来回跑动而不是总是出现在需要的那个队列
•当然,我们可以通过调整优先级告诉系统需要优先执行哪个队列。就比如旁边有一个收银队列的顾客准备好了之后就会呼叫收银员,因此收银员就可以把它作为下一个收银队列跑过去一样

多核多线程时代

•计算机科学家们通过拳打脚踢让硬件科学家们搞出了多核CPU
•终极进化——真·并行处理计算机体系出现啦,大家鼓掌
•可是,好像好多的问题啊

线程的调度

线程调度问题

•实际上,我们任务中的线程不太可能总是自己干自己的事,他们总可能有各种各样的联系
•比如两个线程之间有明确依赖关系
•又比如就像右边的多个收银员需要去更新同一个统计数一样,多个线程由于共享资源,他们总是可能需要同时访问相同的资源
•又由于现成干的事情不一样可能会导致及时后进入等待处理队列的线程需要被优先执行
•线程调度就是负责处理这些让人头疼的事情的。有了它,程序员们就可以不用像计算机科学家那样去考虑我的时间片怎么用了,只要你按照规则,系统帮你处理。哗,终于可以跟隔壁的小花聊个天了
•慢着,少年,too young too simple,规则你都知道么?

线程调度之优先级

•做系统的那个科学家估计当初很懒,他就喜欢顺序执行处于等待队列的线程
•可是总有些事情是需要优先处理的呀,肿么破?比如右边的顾客队列3已经准备好了,顾客队列2还在准备中,应该优先处理顾客队列3吧
•这个好办,给他们分个等级,都排到一个队伍里,等级高在前面按时间先后排队,等级低的在后面,搞掂。额,我好困,再见

线程调度之同步

•刚才的事实告诉我们,系统是靠不住的,科学家也不是都靠得住的,还是要靠我们自力更生的
•于是他们又搞出来同步机制,能够让我们更好的自己安排我们的线程执行顺序

线程调度之等待和事件

•当我们的某个线程需要的条件不满足的时候,它就告诉系统说,等XX事件触发的时候你叫醒我,我先睡会
•系统记录下这个线程的要求,在XX事件没有触发之前都不会分配时间片给它
•XX事件触发了,系统优先唤醒这个线程并分配时间片给它让它继续处理
•线程可以因为等待事件的触发或锁资源的释放进入等待状态,处于等待状态的时候,系统不会分配对应的时间片资源给它,除非它能够等待到它想要的资源
•于是我们的线程总算可以愉快的休息和工作了,啊,生活真美好啊

线程同步之互斥和锁

•我们的线程总是有个性的,有些时候,它在处理某个东西的时候不喜欢别人插一腿,咋办?
•把它锁起来吧,少年,锁起来这段时间它就是你一个人的。别忘了用完了解开锁哦
•锁就是允许你执行排他性操作时用的东东,你加上锁后,请求相同锁的其他线程就处于等待状态,得等锁释放了才能继续依次执行。线程的随机串行化执行也是用锁的哦
•不过,少年,用锁的时候别太嗨,小心死锁哦

线程同步之信号量

•锁只能控制一个一个的执行,我想告诉系统可以同时执行最多N个线程行不行?
•行,为了你这么有想法的少年,我们现在向你隆重介绍信号量这个玩意,它可以允许你同时执行多个线程去访问某个资源
•信号量每使用一个信号,就会减去一个可用数;每释放一个信号,就会加上一个可用数。当可用数为0的时候,请求信号的线程就会像请求锁的线程那样处于等待状态,直到有人释放一个信号,才会继续执行

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 线程基础
    1. 1.1. 进程和线程
    2. 1.2. 只有一个收银队列
    3. 1.3. 多个收银队列一个收银员
    4. 1.4. 多个收银队列多个收银员
    5. 1.5. 新的问题来了
    6. 1.6. 这个问题难不倒我
  2. 2. 线程的进化
    1. 2.1. 单任务时代
    2. 2.2. 多任务时代
    3. 2.3. 单线程时代
    4. 2.4. 多线程时代
    5. 2.5. 多核多线程时代
  3. 3. 线程的调度
    1. 3.1. 线程调度问题
    2. 3.2. 线程调度之优先级
    3. 3.3. 线程调度之同步
    4. 3.4. 线程调度之等待和事件
    5. 3.5. 线程同步之互斥和锁
    6. 3.6. 线程同步之信号量