OS中阻塞与挂起的区别sleep()的实现原理
博客原文
阻塞 VS 掛起
內(nèi)核的sleep()函數(shù)是在掛起原語(yǔ)的基礎(chǔ)上利用定時(shí)器實(shí)現(xiàn)的。阻塞與掛起都是進(jìn)程的狀態(tài),但他們有一些相似之處,也有一些區(qū)別,下面先對(duì)他們進(jìn)行概述,再進(jìn)行比較
阻塞:正在執(zhí)行的進(jìn)程由于發(fā)生某時(shí)間(如I/O請(qǐng)求、申請(qǐng)緩沖區(qū)失敗等)暫時(shí)無(wú)法繼續(xù)執(zhí)行。此時(shí)引起進(jìn)程調(diào)度,OS把處理機(jī)分配給另一個(gè)就緒進(jìn)程,而讓受阻進(jìn)程處于暫停狀態(tài),一般將這種狀態(tài)稱為阻塞狀態(tài)。
掛起:由于系統(tǒng)和用戶的需要引入了掛起的操作,進(jìn)程被掛起意味著該進(jìn)程處于靜止?fàn)顟B(tài)。如果進(jìn)程正在執(zhí)行,它將暫停執(zhí)行,若原本處于就緒狀態(tài),則該進(jìn)程此時(shí)暫不接受調(diào)度。
共同點(diǎn):
1. 進(jìn)程都暫停執(zhí)行
2. 進(jìn)程都釋放CPU,即兩個(gè)過(guò)程都會(huì)涉及上下文切換
不同點(diǎn):
1. 對(duì)系統(tǒng)資源占用不同:雖然都釋放了CPU,但阻塞的進(jìn)程仍處于內(nèi)存中,而掛起的進(jìn)程通過(guò)“對(duì)換”技術(shù)被換出到外存(磁盤)中。
2. 發(fā)生時(shí)機(jī)不同:阻塞一般在進(jìn)程等待資源(IO資源、信號(hào)量等)時(shí)發(fā)生;而掛起是由于用戶和系統(tǒng)的需要,例如,終端用戶需要暫停程序研究其執(zhí)行情況或?qū)ζ溥M(jìn)行修改、OS為了提高內(nèi)存利用率需要將暫時(shí)不能運(yùn)行的進(jìn)程(處于就緒或阻塞隊(duì)列的進(jìn)程)調(diào)出到磁盤
3. 恢復(fù)時(shí)機(jī)不同:阻塞要在等待的資源得到滿足(例如獲得了鎖)后,才會(huì)進(jìn)入就緒狀態(tài),等待被調(diào)度而執(zhí)行;被掛起的進(jìn)程由將其掛起的對(duì)象(如用戶、系統(tǒng))在時(shí)機(jī)符合時(shí)(調(diào)試結(jié)束、被調(diào)度進(jìn)程選中需要重新執(zhí)行)將其主動(dòng)激活
sleep()
之所以將sleep一起討論,是因?yàn)閟leep是一個(gè)很常見(jiàn)的系統(tǒng)調(diào)用,在很多編程語(yǔ)言中,也有對(duì)應(yīng)的函數(shù),所以一起討論可以明白sleep的過(guò)程與阻塞和掛起在底層的效果又有哪些區(qū)別。
sleep():進(jìn)程、線程或任務(wù)(Linux中不區(qū)分進(jìn)程與線程,都稱為task)可以sleep,這會(huì)導(dǎo)致它們暫停執(zhí)行一段時(shí)間,直到等待的時(shí)間結(jié)束才恢復(fù)執(zhí)行或在這段時(shí)間內(nèi)被中斷。
OS中sleep()的實(shí)現(xiàn)
sleep()在OS中的實(shí)現(xiàn)的大概流程:
- 掛起進(jìn)程(或線程)并修改其運(yùn)行狀態(tài)
- 用sleep()提供的參數(shù)來(lái)設(shè)置一個(gè)定時(shí)器。
- 當(dāng)時(shí)間結(jié)束,定時(shí)器會(huì)觸發(fā),內(nèi)核收到中斷后修改進(jìn)程(或線程)的運(yùn)行狀態(tài)。例如線程會(huì)被標(biāo)志為就緒而進(jìn)入就緒隊(duì)列等待調(diào)度。
PS:關(guān)于第二點(diǎn)在這里要介紹一些背景知識(shí):可變定時(shí)器(variable timer)一般在硬件層面是通過(guò)一個(gè)固定的時(shí)鐘和計(jì)數(shù)器來(lái)實(shí)現(xiàn)的,每經(jīng)過(guò)一個(gè)時(shí)鐘周期將計(jì)數(shù)器遞減,當(dāng)計(jì)數(shù)器的值為0時(shí)產(chǎn)生中斷。內(nèi)核注冊(cè)一個(gè)定時(shí)器后可以在一段時(shí)間后收到中斷。
在Linux下,sleep()的實(shí)現(xiàn)流程大概如下:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h>///時(shí)鐘編程 alarm() void wakeUp() {printf("please wakeup!!/n"); }int main(void) {printf("you have 4 s sleep!/n");signal(SIGALRM,wakeUp);alarm(4);//將進(jìn)程掛起pause();printf("good morning!/n");return EXIT_SUCCESS;}綜上所述,內(nèi)核的sleep()函數(shù)是在掛起原語(yǔ)的基礎(chǔ)上利用定時(shí)器實(shí)現(xiàn)的。
調(diào)用以下哪些方法可以使運(yùn)行狀態(tài)的線程進(jìn)入阻塞狀態(tài)?( )A.start( ),yield( ),sleep( ),join( )和wait( )B.start( ),yield( ),sleep( ),join( ),wait( )和stop( )C.yield( ),sleep( ),join( )和wait( )D.yield( ),sleep( ),join( ),wait( )和stop( )參考答案 正確答案:C 解析:運(yùn)行狀態(tài)的進(jìn)程如果調(diào)用了yield( )方法、sleep( )方法、 join( )方法或wait( )方法,或者申請(qǐng)對(duì)象鎖未果、有更高優(yōu)先級(jí)線程進(jìn)入調(diào)度等, 都可進(jìn)入阻塞狀態(tài)。阻塞狀態(tài)的進(jìn)程在獲取到足夠的資源后 ,也可以轉(zhuǎn)入到可運(yùn)行狀態(tài)。編程語(yǔ)言中sleep()的實(shí)現(xiàn)
首先希望大家都了解用戶線程和內(nèi)核線程的概念。編程語(yǔ)言中的線程(用戶線程)與內(nèi)核線程是有著一定的映射關(guān)系的。下面以Java為例,解釋一下用戶線程與內(nèi)核線程的映射關(guān)系,不過(guò)多涉及實(shí)現(xiàn)細(xì)節(jié)。想要了解用戶線程和內(nèi)核線程的關(guān)系模型,見(jiàn) 線程的三種實(shí)現(xiàn)模型
Java線程API通常使用宿主系統(tǒng)的線程庫(kù)來(lái)實(shí)現(xiàn),也就是說(shuō),在Windows中,Java線程使用Win32 API來(lái)實(shí)現(xiàn),而在Linux和Unix系統(tǒng)中使用Pthread。而且,JVM規(guī)范并沒(méi)有指明Java線程如何被映射到底層的OS,而是讓特定的JVM實(shí)現(xiàn)來(lái)決定。例如,在Window XP中采用一對(duì)一模型,而對(duì)于Solaris系統(tǒng),剛開(kāi)始采用多對(duì)一模型,從Solaris 9開(kāi)始采用多對(duì)多模型。
看到這里大家應(yīng)該明白了,用戶線程的sleep()正是利用內(nèi)核提供的sleep()來(lái)實(shí)現(xiàn)的,沒(méi)有內(nèi)核的支持,用戶線程也只能忙等直到規(guī)定的時(shí)間結(jié)束。
參考資料:
1. 《計(jì)算機(jī)操作系統(tǒng)(第四版)》,湯子瀛等著
2. 《操作系統(tǒng)概念(第七版)》,Silberschatz等著,鄭扣根譯
3. Quora 問(wèn)答
4. http://blog.csdn.net/freezgw1985/article/details/5631922
5. https://en.wikipedia.org/wiki/Sleep_(system_call)
6. http://man7.org/linux/man-pages/man3/sleep.3.html
7. http://man7.org/linux/man-pages/man2/nanosleep.2.html
8. http://man7.org/linux/man-pages/man2/alarm.2.html
總結(jié)
以上是生活随笔為你收集整理的OS中阻塞与挂起的区别sleep()的实现原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 汇编中的DW:DW 定义一个字
- 下一篇: OS中关于父子进程的执行顺序和多个子进程