信号量的原理-信号量核心原理
信号量这东西,在咱们那会儿老师讲操作系统的时候,一直一堆死板的名词,像“同步屏障”、“互斥量”、"P 任务”、"V 任务”这些,听得头都大了,恨不得把整个大学课本从头背到尾。
实际上不用如此费劲,咱们把信号量当成一个看家护院的老头要么职场里的老哥来琢磨就行。 想象一下,车间里有一台关键机器,上面有个阀门要关,得两个人一起动手,关完阀门才能开。
这时候,A 要拿钥匙,B 要拿工具,他们得排队,不能抢。
要是两个人都狂点按钮,阀门可能就被扭坏了。信号量就是那个老伙计,手里握着两个牌子,一个“上锁”牌子叫 P,一个“开门”牌子叫 V。 咱们先看看如何“上锁”。A 拿着钥匙(请求)想进车间,但阀门关着,没人来。A 跑去告诉老伙计:“哎,你帮我把锁打开呗。”老伙计得回答说:“行吧,我锁你 100 下(也就是信号量设为 100),这活儿你先干着。”这时候,老伙计手里的锁牌子上就多了个“已占用”的标记。A 心里想:“哎哟,我占了 100 个名额,我目前能不能进来了?”老伙计一看,哎?这数字减了 100,变成了 0。A 要是再想进来,就得再等一遍,不然老伙计还得再次扣个锁。
这就叫“等待”。老伙计手里多出来的这 100 个名额,就是信号量的值。 这时候你就不懂的老伙计会问:“为啥我扣个锁赶明儿,数字还是 100 啊?”实际上啊,信号量是个计数器,是个数字游戏。A 先把 100 记在自己那本账本上,然后给了锁 100。目前老伙计账本上是 0,A 账本上是 100。A 进去干活,干活儿的时候老伙计给 A 发了个工牌(V 操作),老伙计账本上数字多了 1,变成 1。
这时候 A 账本上的 100 减 1 变成了 99。A 走出来了,老伙计账本上是 1,A 账本上是 99。老伙计再要扣个锁,得看账本上剩没剩。 咱们换个场景,再通俗点。想象一个餐厅,只有两个服务员(信号量槽位)。两位客人(进程)想吃红烧肉(关键任务)。 第 1 位客人拿着红烧肉想做红烧肉,但他发现红烧肉被锁住了。他跑去找老伙计:“老哥,帮我打开放红烧肉的牌子呗。”老伙计一听,赶紧把红烧肉锁上,这就好比把门反锁了,钥匙插进去也打不开。老伙计自己先吃口红烧肉,消耗掉一个名额。
这时候,老伙计手里的锁牌子上写着一个数字,比如 99(假设总共有 100 个名额)。 第 2 位客人拿着红烧肉也跑去找老伙计:“老哥,我也想吃,帮我把门打开吧。”老伙计一看,自己手里的锁牌子上是 99 对吧?客人说:“哎,我占 1 个,你减 1 啊?”老伙计立马在锁牌子上扣了个 1,变成 98。 这时候就有难题了。
要是餐厅里确实只有这两个服务员,老伙计手里的锁牌子上是 98,那第 2 位客人就算再跑一趟找老伙计,老伙计也只能把锁牌子上再扣个 1,变成 97。第 3 位客人想去,锁牌子上是 96。老伙计只能扣 1,变成 95。 你会发现,甭管有多少客人想进来,只要锁牌子上有数字,大家都能进去。
这数字到底代表啥?它代表了“还能再进来多少人”。
要是锁牌子上是 0,意味着餐厅彻底乱了,所有客人都进不来,这时候老伙计就得停下来,去问顾客有没有钱付钱,要么去把锁放下来。
这就是 P 操作(等待操作)的核心:老伙计自己先占个号,把锁锁上。 但要是没人进来如何办?比如老伙计不动了,锁牌子上一直是 99,那第 2 位客人被塞进去了,第 3 位客人也进去了,老伙计赶紧释放一个名额。
这时候老伙计手里的锁牌子上就剩 98 了。第 2 位客人要走出来了,他发现自己占了 1 个,那老伙计就发给第 2 位客人一个“去进食”的信号。老伙计的数字变成 99 了。 这时候的数学逻辑实际上挺有意思的。P 操作时,信号量 S 减 1。V 操作时,信号量 S 加 1。
这就像老伙计在记日志。S 一启动是 100。第 1 位客人来了,他拿走 1,变成 99。他进去了,吃了一口,又放回去 1,变回 100。第 2 位客人来了,他也拿走 1,变成 99。他走了,又放回去 1,变回 100。 这里有个细节,咱们得仔细数数。P 操作是减,V 操作是加。当 P 操作时,S 减 1,到了 0,发现 0 了,说明没人能进来了,得找顾客。当 V 操作时,S 加 1,到底是多少? 要是老伙计手里是 0,第 2 位客人进去,拿走 1 变成 -1。老伙计发信号给第 2 位,老伙计手里加 1,变成 0。第 2 位客人拿走 1,变成 0。老伙计再发信号给第 3 位,老伙计手里加 1,变成 1。第 3 位拿走 1,变成 0。老伙计再发信号给第 4 位,老伙计手里加 1,变成 2。
这样循环下去。 故此,S 可能变成 1, 2, 3... 就连更多。它代表可能有几位乘客正在排队,要么正在进食。
要是一个信号量的值小于 0,说明系统出难题了,比如码表坏了,让老伙计把数字设小了,那第 2 位客人进来时,老伙计会发现自己扣了 100 下锁,却只有 2 个名额。
这时候就得报警:系统乱了! 咱们再换个角度想,信号量如何在代码里体现?一般是用一个整数来存。P 操作的时候,先检查数字是不是大于 0。
要是不大于 0,就先把数字减 1,然后忙活待会儿,等别人凑齐 1 个名额了,再通知别人。V 操作的时候,要是数字小于 0(坏了),就直接报错了。
要是数字大于 0,就先把数字加 1,然后忙活待会儿,把数字减 1,再通知别人。 这就好比老伙计手里有一叠钞票。P 操作相当于老伙计拿出一张钞票给排队的人,自己先花掉一张。V 操作就是老伙计把花掉的钞票还回去。P 操作时,老伙计先拿一张(减),再找一张(忙),再放回去(加),这样老伙计手里钞票数量不变。V 操作时,老伙计先给一张(加),再找一张(忙),再拿走一张(减),这样老伙计手里钞票数量还是不变。 可是,要是老伙计手里没钞票(数字小于等于 -1),就不能给排队的人钞票了,这时候就得报警。
要是老伙计手里钞票够多(数字大于 0),能够给排队的人钞票。 再举个例子。假设信号量是 5,相当于有 5 个名额。第 1 个人进来,拿走 1 个,剩下 4 个,老伙计把 1 个发回去,变成 5。第 2 个人进来,拿走 1 个,剩下 3 个,老伙计把 1 个发回去,变成 4。第 3 个人进来,拿走 1 个,剩下 2 个,老伙计把 1 个发回去,变成 3。 到了第 10 个人进来,手里拿走 1 个,剩下 0 个。老伙计没机会发回去了,出于 V 操作需求数字大于 0 才能执行。
这时候老伙计手里是 0,第 10 个人只能死等,要么老伙计自己得去问问顾客有没有钱付钱。
要是老伙计一直等,那顾客就把餐厅堵死了,哪位也吃不到红烧肉。 实际上,信号量的核心逻辑就是“互斥”和“同步”的结合。互斥是说,一个设备不能被两个进程与此同时使用。同步是说,一个进程务必等另一个进程做完某件事才能持续。 咱们再好办对比一下。
比如文件共享,两个人想与此同时打开同一个文件。第 1 个打开,锁上。第 2 个打开,锁不上了,老伙计扣个锁。
然后第 2 个把锁打开,告诉第 1 个“你等了 1 分钟”。第 1 个也打开,锁打开,还跟第 2 个说“你等了 1 分钟”。
这时候老伙计的数字变成 0,两个人都进来了,文件就乱套了。 故此信号量的值一般是个整数,比如 0 表示没锁,1 表示锁了,100 表示有 100 个名额。在操作系统里,P 操作(等待)时,信号量减 1。V 操作(信号)时,信号量加 1。
要是 P 操作时信号量变成 0,说明没人能进来了,得去问顾客。 实际上啊,信号量的本质就是一个数字计数器,用来记录还能抓住多少个“手”。P 操作是减,V 操作是加。P 操作先减,再等,再加。V 操作先加,再等,再减。
要是 P 操作时信号量小于等于 -1,说明系统乱套了。 信号量的原理就是如此好办,就是一个数字在游走。它既记录着有多少个名额,也记录着有多少人在排队。P 操作的时候,数字在削减,人也在等待。V 操作的时候,数字在增添,人也在释放。
要是数字归零,人就没法排了。
要是数字变成负数,那就是游戏终止,系统要崩溃了。 这就解释了为啥 P 和 V 操作如此关键。P 操作保证“不抢”,V 操作保证“通知”。
没有 P 的操作,哪位都能进,文件就打架了。
没有 V 的操作,哪位都不发通知,排队的人就一直等,直到系统崩溃。 故此,信号量不是抽象的数学概念,它就是操作系统里那个具体的、干活的“老伙计”,手里拿着数字,负责分配资源,保证大家公平地进食,不抢饭碗,不饿死。
声明:演示网站所有内容,若无特殊说明或标注,均来源于网络转载,仅供学习交流使用,禁止商用。若本站侵犯了你的权益,可联系本站删除。
