多任務操做系統下一般有3個基本概念:任務、進程、線程。算法
任務:任務是一個邏輯概念,是爲實現某一目的的一些列操做。一次任務可激發多個進程,這些進程相互合做來完成目標。多線程
進程:指一個具備功能的程序在某個數據集合上的一次動態執行過程,它是操做系統進行資源分配和調度的基本單元。函數
進程和程序的區別:程序是一段靜態的代碼,是保存在ROM上的指令和數據的集合,沒有任何執行的概念;而進程是一個動態的概念,它是程序的一次執行過程,它包括了動態建立、調度、執行和消亡的整個過程。spa
線程:進程是系統中程序執行和資源分配的基本單位。操作系統
每一個進程都擁有本身的數據段、代碼段、堆棧段,因此進程切換的操做對系統的開銷較大。爲了提升效率,操做系統引入了線程,也稱爲輕量級進程。.net
線程能夠對進程的內存空間和資源訪問,並與同一進程中的其餘線程共享。所以,線程的切換開銷比進程小的多。一個進程能夠擁有多個線程,其中每一個線程共享該進程所擁有的資源和地址空間,所以,任何線程對系統資源的操做都會給其餘的線程帶來影響,因此應注意多線程中的同步。線程
那麼進程到底擁有那些資源呢,系統又是怎麼對進程進行資源分配和調度的呢?進程
進程的產生:系統首先在新的地址空間裏建立進程、讀入可執行文件、最後開始執行。系統在一開始就會初始化一個進程,叫作init(),在Linux中進程的建立依賴於函數fork(),fork()經過複製當前進程建立一個子進程,子進程與父進程的區別僅僅在於不一樣的PID,PPID和某些資源及統計量。因此init進程是全部進程的上輩進程。而exec函數族則負責讀取可執行文件並將其載入地址空間開始運行。內存
進程的終止:進程終止時系統必須保證進程所佔用的資源回收,並通知父進程。Linux首先把終止的進程設置爲殭屍狀態,此時進程已沒有運行。它的存在只爲父進程提供信息,父進程在某個時間調用wait函數族,回收子進程的退出狀態,隨後子進程佔用的全部資源被釋放。資源
系統是如何管理和調度進程的:Linux內核將率先取得處理器的控制權,再使用調度算法將處理器分配給某個進程。
內核的調度過程:內核將全部進程存放在一個雙向鏈表(進程鏈表)中,鏈表的每一項都是一個task_struct結構體。該結構體包含了進程的全部信息,它能完整的描述一個進程,包括進程的狀態、進程的基本信息、進程的標識符、內存相關信息、父進程信息、與進程相關的終端信息、當前工做目錄、打開的文件信息、所接受的信號等。
其中最爲重要的是task_struct中的state(進程狀態),主要包括:運行狀態(TASK_RUNNING)、可中斷的阻塞狀態(TASK_INTERRUPTIBLE)、不可中斷的阻塞狀態(TASK_UNINTERRUPTIBLE)、暫停狀態(TASK_STOPPED)、殭屍狀態(EXIT_ZOMBLE)、消亡狀態(EXIT_DEAD)。它們之間的轉換關係如圖:
1 進程狀態轉換關係圖
進程所擁有的資源:Linux系統採用虛擬內存管理技術,使得每一個進程都有本身獨立的地址空間。該地址空間是大小4GB的線性虛擬空間。而這4GB的進程空間又分爲兩部分 - 用戶空間和內核空間。用戶空間0-3GB,內核空間3-4GB。用戶進程只有使用系統調用的時候才能訪問到內核空間。每當進程切換,用戶空間就會變化;而內核空間是由內核負責映射,它並不會跟着進程變化,是固定的。每一個用戶進程的用戶空間都是徹底獨立的、互不相干的。
2 進程地址空間分佈圖
用戶空間包括如下幾個功能區域:
只讀段:包含程序代碼(.init .text)和只讀數據(.rodata)。
數據段:存放的是全局變量和靜態變量。其中可讀可寫數據段(.data)存放已初始化的全局變量和靜態變量,BBS數據段(.bss)存放未初始化的全局變量和靜態變量。
棧:有系統自動分配釋放,存放函數的參數值、局部變量的值、返回地址等。
堆:存放動態分配的數據,通常有程序動態分配和釋放,若程序沒有釋放,程序結束時由系統回收。
共享庫的內存映射區域:這是Linux動態連接器和其餘共享庫代碼映射區域。