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