Linux基礎總結-------進程

進程間的相關知識

進程:一個正在運行的程序。一個進程主要包括三個因素

1. fork()

1)函數原型:pid_t fork()

*pid_t是一個宏,其實質是一個整形,且是一個16位的整形(-32768-----32768),因此linux中可以創建的最大進程數爲32768

(2)fork的複製過程

I:先申請一個pid(如果當前進程數已經達到了版本規定的上限,那麼fork時將會出錯);

II:先進行進程描述符(PCB)的複製,在接下來進行進程實體的複製

III:然後進行寫實拷貝

*寫實拷貝:內核並不需要複製整個進程地址空間,只有在寫入的時候才進行資源的複製。而且她的操作是對頁進行操作的

(3)fork函數的簡單應用

EgA.有如下代碼段:

int main(){

pid_t pid1;

pid_t pid2;

pid1 = fork();

pid2 = fork();

}

a.執行這個程序後一共會產生幾個進程?

b.如果其中一個進程的輸出結果是pid11001pid21002其他進程的輸出結果爲?

解:設由shall啓動的進程爲p0;

I:當程序執行到pid1=fork()時,p0啓動一個新進程p1,p1pid1001

IIp0中的fork1001返回給pid1,繼續執行pid2=fork(),此時啓動了一個新的進程爲p2p2pid21002

IIIp0中的第二個fork1002返回給pid2。因此,pid1:1001,pid2:1002;

IV:因爲p2生成時p0中的pid11001,所以p2繼承了p0中的pid11001,但是p2作爲一個子進程它的返回值pid2:0,p2是從第二個fork後運行的,所以,pid11001pid20

Vp1作爲p0的一個子進程,在第一個fork之後將0返回給pid1,在進行第二個fork時,p1產生了一個新進程p3p1中的第二個forkp3pid返回給pid2,由題可知pid21003,因此,p1進程 pid1:0  pid2:1003

IVp3作爲p1的子進程繼承p1中的pid1:0,而它本身也爲一個子進程,所以 pid2 :0

綜上所述:執行這個程序後一共會產生4個進程,分別爲:

p0

p1pid1:0   pid2:1003

p2:  pid1:1001   pid2:1002

P3:  pid1:0      pid2:0

B.fork() && fork()會產生幾個進程?

解:當第一個fork0,不執行第二個fork,則只有一個fork() && fork();當第一個fork>0,執行第二個fork,則會出現兩個fork() && fork();所以總共會有3個進程產生

(4)vfork()

特點:父子進程共享數據段,並且保證子進程先於父進程運行,在它調用exec或者_exit時,父進程纔會被運行

(5)兩種特殊的進程

A. 僵死進程

I.描述:子進程已經結束,而父進程還在繼續

II.處理方法:

a. 程序調用signal(SIGCHLD,SIG_IGN),來忽略SIGCHLD信號,這樣子進程結束後會由內核釋放資源

b. 對子進程的退出捕獲他們的退出信號SIGCHLD,父退出信號時,在信號處理函數中調用waitpid()操作來釋放他們的資源。

B.孤兒進程

I.描述:父進程已經結束,而子進程還在繼續。

II.處理:孤兒進程會由進程號爲1init所收養,並且會爲他們完成狀態收集工作

2. exec()

(1)函數的功能:調用它並沒有產生新的進程,一個進程一旦調用exec()函數,它本身就死亡了。就好比鬼上身了一樣,身體還是你的,但是靈魂和思想已經被替換了-----系統把代碼段替換成新的程序的代碼,在這其中唯一保留的就是進程的ID,對於系統而言,還是同一個進程,只不過是執行另一個程序罷了。

***I.只有fork()vfork()才能創建一個新的進程

II.在使用exec()之前,首先要使用fork(),創建一個子進程,子進程調用exec()函數

(2)exec()函數族

I.說明:

int execlconst char *path,const char *arg,...;

*execv函數的用法類似,只是在傳遞argv參數的時候每個命令行參數都聲明爲一個單獨的參數(“.....”說明參數個數不確定),這些參數要以一個空指針結尾。

int execvconst char *path,char *const argv[];

*通過路徑名方式調用可執行文件作爲新的進程映像

int execleconst char *path,const char *arg,....,char *const envp[];

*execl的用法類似

int execve(const char*pathname,const char *argv[],char *const envp[]);

*參數pathname是將要執行的程序的路徑名,參數argv,envpmain函數的argv,envp對應

int execlpconst char *file,const char *arg,....;

*execl函數類似

int execvpconst char *file,char*const argv[] ;  

*execv函數用法類似  

II.區別

a. 前四個取路徑名做參數,後兩個取文件名做參數

b. 與參數表的傳遞有關(l表示list,v表示矢量vector)。函數execl、execlp和execle要求將新程序的每個命令行參數都說明爲一個單獨的參數,這中參數表以空指針結尾。而execv、execve和execvp則要先構造一個指向各參數的指針數組,然後將該數組的地址作爲這三個函數的地址。

3.進程間通訊

(1)進程間通訊的幾種方式

管道  消息隊列  信號量   共享內存   套接字

A. 管道

a. 實現進程間通訊的原理:

就像現實中管道的兩端一樣,由一個進程進行寫操作,其餘的進程進行讀操作。如果管道爲空,那麼read會阻塞;如果管道爲滿則write會阻塞。

b.分類

管道可以分爲有名管道和無名管道兩類。他們之間的區別是:

I.有名管道:可以在任意進程之間進行通訊,通訊是雙向的,任意一端都可讀可寫,但同一時間只能一端讀,一端寫。

II.無名管道:只能在父子進程間通訊,不能在網絡間通訊,並且是單向的,只能一端讀另一端寫。

c.特點:通訊數據遵循先進先出的原則

B.消息隊列

a. 特點:  I.是消息的鏈表。具有特定的格式,存放在內存當中,由消息隊列標識符標識。

II.消息隊列允許一個或者多個進程向他寫入與讀取消息。

III.消息隊列可實現消息的隨機查詢,不一定要以先進先出的順序讀取,也可以按照類型進行讀取。

b.相關函數

C.信號量

a. 概念:用來同步進程的特殊變量;

b. 手段:通過控制程序的推進速度,使得同一個過程只有一個進程訪問;

c. 操作方式:對信號量進行操作使用p v操作,p v操作都是原子操作;

   *p操作:獲取資源,信號量的值減1;

*v操作:釋放資源,信號量的值加1

D.共享內存

a. 實現原理:享內存區域說白了就是多個進程共享的一塊物理內存地址。假設有10個進程將這塊區域映射到自己的虛擬地址上,那麼,這10個進程間就可以相互通信。由於是同一塊區域在10個進程的虛擬地址上,當第一個進程向這塊共享內存的虛擬地址中寫入數據時,其他9個進程也都會看到。因此共享內存是進程間通信的一種最快的方式。

E.套接字

4. 信號

(1)signal()函數【響應方式】

signal(參數1,參數2);

參數1:需要進行處理的信號;

參數2:處理的方式(1.默認 2.忽略 3.自定義)

Eg:a.signal(SIGINT,SIG_ING)

*SIG_ING代表忽略SIGINT這個信號

b.signal(SIGINT,SIG_DEF)

*SIG_DEF表示默認操作(對於大多數信號,系統的默認操作是結束該進程)

(2)kill()函數【是一個信號發送函數】

int kill(pid_t pid,int sig)

*pid = 0:信號被髮送到和當前進程在同一個進程組的進程

pid = 1:信號發給所有進程表中的進程;

          @@@ raise()也是一個信號發送函數,不過他可以允許進程向自己發送信號。

int raise(int sig);

5. 進程狀態轉移圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章