信号量 semaphore 机制可实现基于条件变量 condition variable 的管程 monitor 机制
多 CPU
判断:在多 CPU 系统中,仅通过 CPU 中断和屏蔽指令,就能实现对临界区代码的互斥保护。
这个说法是错误的。因为有多个 CPU ,所以单个 CPU 的中断不能保证互斥保护。
任何时刻只有一个线程访问缓冲区,这是互斥访问。
互斥是操作系统内核的几个特点之一,互斥是共享的一个详细说明。共享:程序间“同时”访问,互斥共享各种计算机资源。这里的同时是加了引号的,表示不是真正意义上的同时,只是计算机认为,或者宏观上来看是同时的,实际上某一个具体的时刻, 微观上来看,肯定只能一个访问这个资源吧。比如说,一个人看起来同时运动和学习,实际上不可能一边运动一边学习吧,肯定是学习完了运动,或者运动完了学习。就是这样。
操作系统内核还有几个特点。并发:计算机里面同时存在多个程序,并发非常有意思,比如我考研,我需要并发,英语,数学,专业课之类的,但是我知道,最重要的就是数学和专业课,数学决定能否考高分,专业课决定能否进面试。我真想专业课考 90 分以上啊。
虚拟:这也是操作系统内核的一个特征。表示的意思是,让程序误以为自己独占计算机,实际上不可能,这个可能和一个渣男,让女孩误以为只有自己一个女朋友。实际上渣男对每个女孩都是一样,给她们无限的温柔和幻想。
异步:服务的完成时间不确定,也可能失败。考研可能失败吗,不可能失败,我一定可以考上。并且就是今年一次就考上。
看了一下 ppt 很多期末考试题确实就是 ppt 里面的原话,所以还需要整理一下 ppt 里面的知识点。慢慢来呗,反正两个月的时间,足够做很多事儿了。
借这个题,复习一下同步与互斥这个章节吧。除了实验部分,其他部分的 ppt 全部看一遍。我感觉直接看,直接理解就可以了。这个东西并不是那么高深的东西,这又不是实实在在的科研,是很多年前的东西了,怎么可能学不会。
如果是独立的,会好一点,会有一些好处,比如说是确定的,可以重现的,那么为什么,我们要共享资源呢?
原子操作是,不会被中断的操作,也不可能失败,意思就是,很小的一个操作,没有任何难度,可以认为是一个基本单位吧。比如说,我写一个 1 + 1 = 2,我知道考研数学是一个复杂的工程,但是我这个基本的运算就是我的原子操作,或者我做一个简单的计算。计算机做一个简单的加减法,当然这个加减法可能都已经比较复杂了,只是随便举一个例子。
加锁可能导致,冰箱里面有食物,但是别人无法获得。因为我们去买面包,所以给冰箱加了锁,但是加了锁别人就无法拿冰箱里面的冰棍了。
忙等待,busy waiting ,等待的时候,不能做其他的事情。也就是说,忙着等待,专心等待,说实话,这个有点浪费时间了。在这个信息时代,也许利用这个时间,背几个英语单词,争取英语考 70 分才是正经的。
lock.acquire()
加锁
lock.release()
解锁并唤醒任何等待中的线程。
写到这里,我先分析一下,最开始那道题。
中断屏蔽可以实现单 CPU 的临界资源的互斥访问。屏蔽中断,就是屏蔽干扰,开中断就是允许中断,中断就是打断当前正在进行的进程。实际上计算机的这个操作系统,和我们人类非常类似。但是一个 CPU 的屏蔽中断没有效果,比如说另一个 CPU 没有屏蔽中断,那么另一个 CPU 的进程可以进入临界区。临界区是 critical section , 临界区的代码必须满足互斥性,多个进程不能同时进入临界区。
我看了一下 ppt ,后一张 ppt 就介绍了 ppt ,果然 ppt 是宝藏,可惜我的时间有限,不能仔细慢慢研究 ppt 了。我也希望,我以后再也不用研究这个 ppt 了,我只想今年就考上。这是最好的结果。
空闲则入,就是临界区里面没有线程,那么都可以进去。
进程和线程的关系,类似于工厂的车间和工厂的工人之间的关系。
感觉进程更大一些,线程更小一些,但是线程可能影响全局的。不要轻视线程。
忙则等待:就是临界区里面有线程,别的线程就不可以进入临界区。这个很难受,就像你需要使用临界区,需要使用某个资源,但是这个资源被别人占领了。你只能等待。等待是今晚的康桥。
有限等待,线程不可能无限地等待。这个很好理解,比如说,一个女神,一个男孩喜欢,女神让他等等他,好呀,男孩肯定愿意,但是等了一年,两年,最后,男孩懂了,根本不可能等待这个所谓的女神的,再等下去,自己的青春也结束了,所以就结束了等待。
让权等待:就是知道自己等不到了,就放弃了,并且把之前的记忆全部清空,就像是从来没有认识过一样。把过去清空,让后来的人,有地方可以存放。
使能中断,原来不是敲错字了,而是本来就是这么描述的。我真是服了。
禁用硬件中断
这是啥意思,是硬件中断,还是禁止用硬件中断?disabling hardware interrupts ,还是英文没有歧义一些,中文的理解太多太多了。很容易引起歧义,中文之华美。
禁用硬件中断,就是说硬件也不能中断临界区的线程,保证了操作的原子性和数据的一致性。闭关修炼,不让别人打扰自己,这个更狠,就是别人用物理来干扰,试图中断,都被 disabling 了。
peterson turn + flag
好多具体的算法,考这个我真的老实了。
难怪网上说计算机考研比较难,就是因为这个东西,要是真的研究,就是深不见底,但是什么是刚好考试考察,并且自己可以掌握的呢。我只想要 os 能稳定地拿 20 分以上就可以了。
锁 lock
是一个二进制变量,只有两种可能,就是锁定或者解锁。稍微看了一下,真题没有考的特别深入,要是考的特别深入,真的就是跪下了,根本啥也写不了,专业课的难,不是说逻辑上非常难,当然数据结构可能逻辑上非常难,另外几门,关键就是记忆理解上面的难,并且东西多。没有形成自己的一个框架。
总结来说,禁用中断,仅限于单处理器,意思就是对于多处理器没效果。为什么呢?
按照我的理解,就是一个核进行了禁用硬件中断,也就是中断屏蔽,然后其他的核,可能没有中断,那么某个临界区线程正在执行的时候,可能有其他的线程进入临界区,出现并发冲突。
硬件原子操作指令,单处理器,多处理器都可以使用。实际上就是用锁。所以锁应该是考试的重点。
信号量 samaphore
dijkstra 这个真是计算机大佬啊。一个整型变量 sem 和两个原子操作构成。这就是 pv 操作吗。荷兰语,难道这个大佬是荷兰人?查了一下,确实是荷兰人。
p 是减少,v 是增加,就是对这个 sem 这个变量进行操作。两个原子操作就是增加和减少。p v 表示的就是减少和增加。
p 可能阻塞,v 不可能阻塞。这个很好理解,p 是减少,就类比取钱就可以了。比如说,我们去取钱,可能跨银行不行,但是 v 增加,存钱,不存在这个问题,不管啥银行,我们想要增加自己的存款,所有银行都是求之不得的,都愿意你把钱存到他们银行。
信号量的使用
互斥访问,条件同步。
条件同步的意思就是,进程和线程,在满足特定的条件之前,是暂停的,满足了特定的条件之后,才可以被唤醒。比如,红灯变绿,我们才可以通过人行横道。
pv 操作必须成对使用,这个就像是括号,一个左括号,一个右括号一样。p 操作是保证互斥访问资源,v 操作是,在使用之后释放资源。
生产者消费者问题
有界缓冲区的生产者和消费者问题。生产者放在缓冲区。消费者从缓冲区里面取出数据来处理。任何时刻只有一个生产者或者消费者可以访问缓冲区。
缓冲区是啥???
《安宁》听着孙燕姿的歌儿,我相信自己一定可以考上这个研究生。要加油。
缓冲区是 buffer ,互斥锁,mutex ,阻塞队列,blocking queue
缓冲区空的时候,缓冲区必须等待生产者,条件同步,也就是说,只有生产者生产了数据才可以。然后缓冲区满的时候,必须等待消费者,就像是,生产者就像是输入,消费者就像是输出。
我们考试就是输入和输出,现在就是输入,考试是输出,为了让考试的时候的输出更猛一些,我们现在要多进行输入,还有,多输出,形成自己的理解。
管程和条件变量
monitor 和 condition variable
monitor 不是监视器的意思吗。
查了一下,确实是。奇怪了。
pv 操作和锁都有缺点,所以引进管程 monitor 。
管程 monitor 是多线程互斥访问共享资源的数据结构。前面锁好像也是这个定义。信号量也是。
总结了一下,都是实现互斥访问的手段和方式方法。
任一时刻,只有一个线程执行管程的代码。正在管程的线程可以临时放弃管程的互斥访问,等待事件出现时恢复。
主动让出锁,条件满足再抢夺锁?实际上也不是抢夺吧,释放之后需要重新排队访问。比如说,图书馆座位是一个管程,然后,我们选了一个座位,我们是线程,我们中午要回去吃饭,睡觉,我们退了这个座位,就是临时放弃了管程的互斥访问,然后我们下午休息好了,重新等待队列,等图书馆的人退座之后再选这个座位。
放弃管程,执行 wait ,被通知,如 signal 之后,可以被唤醒。
管程里面是互斥的,同一时刻,管程里面只能有一个线程。
入口队列管理未进入管程的线程和进程。
条件变量
条件变量 condition variable 和 互斥锁 mutex 结合使用,可以实现线程间的同步和互斥。
同步的意思实际就是线程之间是有一定的逻辑关系,先后顺序的。也就是说,比如说,我要先吃透了高数,才能学好概率,很多概率的题,都需要高数的知识。
线程拥有互斥锁 mutex 的时候,可以修改或者访问共享资源。互斥锁 mutex 就像是尚方宝剑一样。就是有这个东西,就表示拥有一个访问和修改的特权,access 感觉就是这个感觉。
共享的资源被其他的线程占用了,当前线程就是被阻塞了,那么我们就可以让出互斥锁,等待条件变量唤醒。就是当前的这个被阻塞的线程,进入了条件变量的等待队列里面。
看了一下真题,感觉不好说,必须把知识点记在脑子里面,因为考察的形式确实是多样的,只能以不变应万变。。。
但是远没有我设想的那么那么困难,实际上就是简单的一些考察,绝对不是想要为难考生。
唤醒使用的紧急队列。紧急等待队列,唤醒别的线程的这个线程,被挂起,挂到紧急等待队列里面,紧急等待队列的优先级高于条件变量等待队列。
紧急等待存放因为 signal 或者 notify 主动让出锁的线程。这个意思就是,我本来拥有这个权限,现在我把这个权限让给别人,但是下次我需要访问的时候,我的权限或者说,优先级是比较高的。这个和日常生活中也非常非常类似。
条件变量等待队列里面的线程是因为共享资源被其他线程占用,所以阻塞了,阻塞执行 wait 操作等待。
幸好后面也没有太多的内容了。我真是有点头大,这么多内容。我。。。一定能学会。至少拿到一个 90 分的水平。加油。加油,不要让梦想埋没啊。
enter 线程进入管程之前,需要获得互斥访问权,lock ,就是互斥访问锁 mutex ??
mutex 是专门为管程,monitor 设计的锁,实际上这里就是没有作严格的区分。
离开,leave ,就是先看紧急等待队列里面是否有线程,如果有,就把自己的 mutex 赋予给紧急等待队列里面的线程,如果没有,就唤醒入口等待队列里面的线程,这个入口等待队列就是条件变量等待队列吗?
好像不是,入口等待队列和条件变量等待队列是两种不同的队列。
entry queue 和 condition queue
entry queue 是按照 FIFO 来看的。就是先进先出,就是按照顺序访问。公平地竞争锁。
一般来说,condition queue 里面的线程被 signal 唤醒之后,也是进入 entry queue 按照顺序参与锁的竞争。
wait 就是阻塞自己这个线程,然后把自己这个线程挂到 condition queue , 然后释放 mutex , 唤醒一个 entry queue 的线程,或者多个线程,都是可以的。就是说,我告诉别人,我不可以,然后我把自己的一些资料送给别人,我说,我不可以,你们上吧。
但是,我一定可以呀。
加油就完事了。
signal 是唤醒 condition queue 里面的一个线程。把自己线程的 mutex 赋予 condition queue 里面的线程,自己把自己挂到紧急等待队列。urgent queue
大概就是这样。
我发现自己从 1563 开始看,看到了 1641 ,看了 80 页的内容,我非常非常棒。做得非常非常好。
总共是 1900 页的内容,按照这个速度,考试之前完整地看一遍,都是一个挑战呀。。。
但是事在人为,我们一定可以的。加油。会赢的。
产生冲突之后,怎么操作呢?比如说一个线程 t1 被阻塞了,执行了 wait 操作,然后另一个线程 t2 让线程 t1 需要满足的条件满足了,使用 signal 唤醒了 t1 , 但是 t1 和 t2 不可以共存,这个时候执行 t1 还是执行 t2?
这个时候,应该是执行哪个???
Hoare monitor 是执行 t1,t2 等待。t1 执行完成之后 leave monitor , 然后 t2 enter monitor
MESA / Hansen 是 t2 执行,t1 等待,t2 leave monitor 之后,t1 可能执行,可能等待,因为可能要重新竞争,因为 entry queue 里面有很多线程 thread 都需要 enter monitor
Hoare / MESA / Hansen 表示几种不同的 monitor 类型。
signal 之后直接赋予 mutex 还是重新竞争 mutex
这是两种不同的策略,直接赋予的话,减少了上下文切换,重新竞争的话,更加公平。
这个东西,类似于,我用一个东西,用完之后直接给你,还是说,用完之后放回去,放到一个地方,然后所有人都可以去该地方取这个东西,被唤醒的 thread 需要重新竞争这个 mutex ,可能被其他的 thread 抢先。
Meas monitor 是让 t2 signal t1, 然后 t2 enter, t1 进入 entry queue 重新竞争 mutex
Hansen monitor 是 t1 不需要重新竞争 mutex ,直接在 t2 执行完了之后执行 t1
条件变量的实现
condition variable 的实现
require(lock)
表示 thread 尝试获取 mutex / lock ,这里就是为了尝试获取 mutex 吧。
schedule 主要是做进程选择和上下文切换,根据进程的优先级做一个选择。
好像就是几个问题,读者写者问题,哲学家进餐问题,银行家算法等。就这么点东西,要是学不会我真的和自己爆了,妈的,一定要学会。我真的受不了了。这个东西,真的真的没有那么难。我一定可以做到的。
我努力地想哭泣,却哭不出泪滴,一次又一次的灰心,才发现早已麻痹。《安宁》
bounded buffer
有界缓冲区的生产者消费者模型,bounded buffer 类似于一个仓库,生产者是送货的司机,消费者是搬运货物的工人,仓库是满的的时候,司机等待工人把货物搬走,仓库是空的时,工人等待司机运送货物过来。
这就是缓冲区的生产者消费者模型。
bounded buffer deposit
有界缓冲区的存入。
java 支持 monitor
cpp 支持 condition variable