Linux系統程式設計之程式介紹

安全劍客發表於2019-08-28
我們平時寫的 C 語言程式碼,透過編譯器編譯,最終它會成為一個可執行程式,當這個可執行程式執行起來後(沒有結束之前),它就成為了一個程式。
一、程式概述

我們平時寫的 C 語言程式碼,透過編譯器編譯,最終它會成為一個可執行程式,當這個可執行程式執行起來後(沒有結束之前),它就成為了一個程式。
程式是存放在儲存介質上的一個可執行檔案,而程式是程式執行的過程。程式的狀態是變化的,其包括程式的建立、排程和消亡。程式是靜態的,程式是動態的。
在   系統中,作業系統是透過程式去完成一個一個的任務,程式是管理事務的基本單元。程式擁有自己獨立的處理環境(如:當前需要用到哪些環境變數,程式執行的目錄在哪,當前是哪個使用者在執行此程式等)和系統資源(如:處理器 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 執行。

等待態:

程式因不具備某些執行條件而暫時無法繼續執行的狀態。
這裡需要注意,就緒態和等待態都是不執行,但它們是有區別的,就緒態是指滿足條件,時間沒到,等待態是不滿足條件。
同樣的,程式的這三種狀態可以相互轉換:
Linux系統程式設計之程式介紹Linux系統程式設計之程式介紹

執行態-->等待態:

正在執行的程式因等待某種事件發生而無法繼續執行時,便從執行狀態變成等待狀態

等待態-->就緒態:

處於等待態的程式,若其等待的事件發生,於是程式由等待狀態變成就緒態

就緒態-->執行態:

當就緒態的程式所等待的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系統程式設計之程式介紹Linux系統程式設計之程式介紹
所以,在 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;
}

執行結果:
Linux系統程式設計之程式介紹Linux系統程式設計之程式介紹

原文連結:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2655339/,如需轉載,請註明出處,否則將追究法律責任。

相關文章