您好,登錄后才能下訂單哦!
我們平時寫的 C 語言代碼,通過編譯器編譯,最終它會成為一個可執行程序,當這個可執行程序運行起來后(沒有結束之前),它就成為了一個進程。 |
我們平時寫的 C 語言代碼,通過編譯器編譯,最終它會成為一個可執行程序,當這個可執行程序運行起來后(沒有結束之前),它就成為了一個進程。
程序是存放在存儲介質上的一個可執行文件,而進程是程序執行的過程。進程的狀態是變化的,其包括進程的創建、調度和消亡。程序是靜態的,進程是動態的。
在
Linux 系統中,操作系統是通過進程去完成一個一個的任務,進程是管理事務的基本單元。進程擁有自己獨立的處理環境(如:當前需要用到哪些環境變量,程序運行的目錄在哪,當前是哪個用戶在運行此程序等)和系統資源(如:處理器 CPU 占用率、存儲器、I/O設備、數據、程序)。我們可以這么理解,公司相當于操作系統,部門相當于進程,公司通過部門來管理(系統通過進程管理),對于各個部門,每個部門有各自的資源,如人員、電腦設備、打印機等。
我們現在的電腦基本上都是多任務,我們聊著 QQ 的時候,同時可以看著視頻,這里相當于 QQ 和視頻兩個程序同時運行著(兩個進程)。早期的時候,電腦的 CPU 是單核的(單核理論上只運行操作一個任務),那它是如何做到多任務的呢?這就涉及到進程的調度策略。現在給大家舉這么一個例子,有 A,B,C 三個進程,在我們單 CPU 的情況下,每一個時刻只有一個進程在運行,如果 A 運行完,B 運行,B 運行完,C 運行,C 運行完,A 運行,而 CPU 的運算速度足夠快,A 兩次運行時間間隔足夠短,從宏觀上就我們就看到 A,B,C 好像同時運行,這就是實現單 CPU 運行多個任務的核心原理,通過時間片輪詢調度策略實現多任務(更多詳情,請看《Linux 進程調度淺析》)。
從上面的例子,我們可以得知,對于 A 進程而言,有時候在運行,有時候沒有運行,兩個狀態不一樣,所以,進程是有狀態的,同時,狀態是可以相互進行轉換的,從執行的狀態轉換為不執行的狀態,這里,我們可以把進程運行的整個生命周期簡單劃分為三種狀態(實際上不指這三種狀態):就緒態、執行態、等待態。
進程已經具備執行的一切條件,正在等待分配 CPU 的處理時間。
該進程正在占用 CPU 運行。
進程因不具備某些執行條件而暫時無法繼續執行的狀態。
這里需要注意,就緒態和等待態都是不執行,但它們是有區別的,就緒態是指滿足條件,時間沒到,等待態是不滿足條件。
同樣的,進程的這三種狀態可以相互轉換:
正在執行的進程因等待某種事件發生而無法繼續執行時,便從執行狀態變成等待狀態
處于等待態的進程,若其等待的事件發生,于是進程由等待狀態變成就緒態
當就緒態的進程所等待的cpu時間片一到來,進程就會從就緒態變成執行態
處于執行狀態的進程在其執行過程中,因分配給它的一個時間片已用完而不得不讓出cpu,于是進程從執行狀態轉變成就緒狀態
為了讓大家更加清晰地了解三種狀態的轉換,給大家舉一個lh買火車票的例子。
lh匆忙地趕去火車站買火車票,太著急了,到了售票廳才發現忘記帶身份證,這時候,就算 lh排隊也沒用,因為 lh不具備買票的條件(沒帶身份證),這時候的 lh屬于等待態。
lh給它對象打電話,讓她把身份證帶過來,等會,身份證送到了,這時候,lh可以去排隊買票了,只是時間到,lh就可以買票了,這時,lh屬于就緒態。而這過程是由等待態轉換到就緒態。
等了 10 分鐘,終于到 lh了,lh開始買票,這時候, lh屬于執行態。而這過程是由就緒態轉換為執行態。
而在買票的過程中,lh的對象打電話給他,讓 lh也幫她買一張火車票,但是, lh沒有她對象的身份證,接著,lh繼續等他對象送身份證,這時候,lh由執行態轉換為等待態。
假如是這么一種情況,lh買火車票是給公司的同事買的(需要買 100 多張票),在買著票的過程中(執行態),后面還有很多人在排隊,后面排隊的人肯定不爽,這時售票員就說,20分鐘后,如果你還沒處理完,請你到后面排隊。結果,lh花了 20 分鐘還是沒有處理完,于是,乖乖地到后面重新排隊,這時候,lh由執行態轉換為就緒態。
對于操作系統而言,它需要控制很多進程,同時,每個進程都有不同的狀態,系統如何知道 A 執行完到 B 執行而不是 C?系統如何協調控制進程呢?
當我們運行一個程序使它成為一個進程時,系統會開辟一段內存空間存放與此進程相關的數據信息,而這個數據信息是通過結構體( task_struct,ubuntu12.04中打開 /usr/src/linux-headers-3.2.0-23/include/linux/sched.h 可以找到 task_struct 的定義 )來存放,我們把這個存放進程相關數據信息的結構體稱為進程控制塊。
操作系統就是通過這個進程控制塊來操作控制進程。更多詳情,請看《 Linux 進程管理》。
進程控制塊是操作系統中最重要的記錄型數據結構。進程控制塊記錄了用于描述進程進展情況及控制進程運行所需的全部信息,它是進程存在的唯一標志。進程控制塊里有很多信息,其中比較重要的是進程號,至于其他的一些信息我們不在這詳細討論。
每個進程都由一個進程號來標識,其類型為 pid_t(無符號整型),進程號的范圍:0~32767。進程號總是唯一的,但進程號可以重用。當一個進程終止后,其進程號就可以再次使用。
所以,在 Linux 下面所有的進程都由 init 進程直接或者間接創建。
接下來,再給大家介紹三個不同的進程號。
進程號(PID):
標識進程的一個非負整型數。
父進程號(PPID):
任何進程( 除 init 進程)都是由另一個進程創建,該進程稱為被創建進程的父進程,對應的進程號稱為父進程號(PPID)。如,A 進程創建了 B 進程,A 的進程號就是 B 進程的父進程號。
進程組號(PGID):
進程組是一個或多個進程的集合。他們之間相互關聯,進程組可以接收同一終端的各種信號,關聯的進程有一個進程組號(PGID) 。這個過程有點類似于 QQ 群,組相當于 QQ 群,各個進程相當于各個好友,把各個好友都拉入這個 QQ 群里,主要是方便管理,特別是通知某些事時,只要在群里吼一聲,所有人都收到,簡單粗暴。但是,這個進程組號和 QQ 群號是有點區別的,默認的情況下,當前的進程號會當做當前的進程組號。
Linux 操作系統提供了三個獲得進程號的函數
getpid()、getppid()、getpgid()
。
所需頭文件:
include include pid_t getpid(void);
功能:
獲取本進程號(PID)
參數:無
返回值:本進程號
pid_t getppid(void);
功能:獲取調用此函數的進程的父進程號(PPID)
參數:無
返回值:
pid_t getpgid(pid_tpid);
功能:獲取進程組號(PGID)
參數:pid:進程號
返回值:參數為 0 時返回當前進程組號,否則返回參數指定的進程的進程組號
示例代碼如下:
include include include int main(int argc, char *argv[]) { pid_t pid, ppid, pgid; pid = getpid(); printf("pid = %d ", pid); ppid = getppid(); printf("ppid = %d ", ppid); pgid = getpgid(pid); printf("pgid = %d ", pgid); return 0; }
運行結果:
原文鏈接: https://www.linuxprobe.com/linux-system-programming.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。