NJUOS-6-并发控制:同步
本文最后更新于:2 年前
上节课互斥,这节课就是同步啦。主要讲述的就是一些和同步相关的内容昂!!!互斥是手段,同步是目的,同步本质上是一种更为复杂的互斥。
本次课上将会学会:如何在多处理上协同多个线程完成并行的任务。
线程同步
两个或者两个以上,随着时间变化的量,在变化过程中保持一定的相对关系。
- Asynchronization = !Synchronization,要让并发程序,保持步调!!!
生产者-消费者问题
太经典了…多线程有逻辑上的先后关系,借助互斥量等方法,完成业务逻辑。互斥量就是帮助实现这个过程的手段。
互斥锁(Spin)
左括号相当于是队列的生产者,右括号相当于是队列的消费者。是否可以使用类似于Spin这种方式,实现呢?
1 |
|
- 检测工具,自己写的自己测一下噻
1 |
|
./a.out 5 | python3 checker-py 5
- 自旋消耗性能 -> Sleep,条件满足别人再把我唤醒!!!
条件变量(CV)
生产者&消费者
- 例子:
1 |
|
- 压测工具&代码:
1 |
|
上面的程序,模拟了C语言一个Producer,两个Consumer的行为。 -> 继而可以搭配model-checker,完成正确性的校验,更快找到问题!!!(Small Scope Hipothesis -> 小范围假设,找到引发问题的最小原因,建模 -> model-checker等工具,分析并发程序的Bug原因)
上面这个出问题了…如何debug? 第一步:能否找到隔离触发这个bug的最小条件(比如加一个Consumer试试?)-> 发现!!!有个Consumer在不该唤醒的时候,被唤醒了!!!经典问题!!!
- Consumer在cond_signal,全局就一个信号量,导致唤醒了另外一个Consumer!!! -> 解决方法:
- 两个条件变量,一个专门唤醒Consumer,另外一个专门唤醒Producer,这样不会唤醒混了。
- 就算是唤醒了Consumer,它也不能直接去执行!!!还要检查,是否满足自己执行的条件!!!
1 |
|
if(count == n) 和 if(count == 0) -> 把if改成while昂!-> 无所谓,你不能先出手…你必须符合条件才能执行哇…
把你唤醒,你不一定能执行!!!唤醒的也不一定满足条件,一定要记得while检查,而不是if,尤其涉及到这种条件判断和Sleep耦合的…你醒来,条件就不一定满足了!!!
并行计算实现
- 上面这个就是可以实现并行计算,waiting for job,当创建了任务的时候,job就会被取出来执行。
- 有了线程池的初版模型昂!!!
程序并行化
画一个DAG出来昂!!!
- 比如一个DP算法,我们可以根据递推公式,找到每一个元素之间的依赖关系。
- 可以使用拓扑排序,找到每一个Layer(BFS)
1 |
|
第一层可执行的任务:a,b,c
第二层可执行的任务:d, e
第三层可执行的任务:f
第四层可执行的任务:res
- 每一层的任务之间没有依赖关系,可以并行,就可以交给不同的线程去执行,这样就实现了任务的并行化。甚至可以引出MapReduce方法!!!
奇怪的问题
三个一组,三个一组 -> 构成水分子
- jyy你真行啊。。。直接level up,自己出题当其中考试题,同学们都说谢谢你嗷!!!
CV解决的核心:while循环的条件是啥?啥时候可以打印<,>和_对不?判断现在输出的状态 -> 掌握全局状态机的分叉!!!
- 不用动脑子,构造一个状态机 -> from … to …就行哇!!!
1 |
|
全部notify_all起来,符合条件就打,不符合条件就睡。。。这不就很简单???!!!不用动脑子!!!
- 推荐条件变量,绝对万能!!! -> 缺陷:在我看来,本质就是互斥锁plus,互斥锁 + sleep实现饿了同步而已。
信号量(Signal)
本质就是拓展了互斥锁,成了一个🔒库。可以协调多个线程的同步问题。-> or 带有计算器的锁,这么想也对!!!
- 可以作为互斥锁来使用,同时信号量封装好的机制,能帮助我们很优雅实现生产者和消费者。
1 |
|
明显简单,“单位资源”明确的情况下很方便,很好用。但是遇到复杂情况,例如上面奇怪的问题,明显条件变量复杂度更高,灵活性也越高!
- 小心处理,可能会出现一些我们上面没考虑到的并发问题。
哲学家吃饭问题
引发DeadLock的问题 -> Debug简单,可以打印出每个线程手上持有锁的情况。
- 很重要的思想:反复告诉我们的就是,很多奇奇妙妙的算法,方法。不要尝试去这么做,有万能的方法就用万能的方法。代码的量级上去了之后,“聪明”会带来“困难”。 -> 互斥锁最简单!!!试试呗!!!
- 加个互斥锁,想要操作的哲学家看看,如果左右不能全部拿起来,就放下来等待!
- 如果拿的起来,就吃饭!!!
- 使用信号量(复杂的):
1 |
|
可控性差,造成死锁了。没有办法,在“抢不到两个”叉子的时候,放下手中的叉子。P操作,在你抢不到叉子的时候,直接就睡了,手上的叉子放不下来……
- 成功的尝试(万能的互斥锁)
1 |
|
一把互斥锁,就很方便昂!!!全部人一把锁,一个一个哲学家的抢,抢不到就释放锁,抢到了,就可以吃饭了昂!!!
- 成功的尝试(忘了信号量,让一个人集中管理叉子吧!“Leader/Follower” - 生产者/消费者)
服务员统一管理叉子!!!分布式系统中非常常见的解决思路 (HDFS, …) -> 你想吃?服务员帮你看看,能吃就吃,你别自己去动筷子昂!!!
1 |
|
集中式的算法,远远比分布式的算法,容易弄对的多!!!一个服务员是可以对于所有的叉子是可以有一个清楚的认识的!!!Master/Slave!!!!!
Summary
抛开 workload 谈优化就是耍流氓