Linux程序控制 2 程序等待 程式替換

2021-10-05 05:50:45 字數 4578 閱讀 8028

我們知道, 子程序先退出, 父程序如果不管不顧, 就會導致殭屍程序, 進而造成資源洩漏等嚴重問題

一旦產生殭屍程序, 「殺人不眨眼」的kill -9也無能為力, 因為沒有辦法殺死乙個已經僵死的程序

那麼如何避免產生殭屍程序呢???

父程序通過程序等待的方式, **子程序資源, 獲取子程序退出資訊 .

這裡先說一下阻塞和非阻塞:

阻塞: 為了完成某個功能發起乙個呼叫, 若當前不具備完成功能的條件, 則一直等待不返回

非阻塞: 為了完成某個功能發起乙個呼叫, 若當前不具備完成功能的條件, 則立即報錯返回

非阻塞相較於阻塞, 對cpu利用更加充分, 因為不需要再一直等待了, 但是必須迴圈進行操作

程序等待的方法

wait函式:阻塞等待任意乙個子程序退出, 獲取子程序的返回值放到status指向的空間中, 並且釋放子程序資源, 返回退出的子程序pid

pid_t wait

(int

*status)

;返回值:

成功後,返回終止子程序的程序號;如果出錯,則返回-

1status引數:

獲取子程序退出狀態,不關心則可以設定成為null

如果status不為null

,則wait

()和waitpid

()將狀態資訊儲存在它指向的int中

waitpid函式:不僅可以等待任意乙個子程序的退出, 也可以等待指定的子程序的退出, 並且可以設定為非阻塞

pid_t waitpid

(pid_t pid,

int*status,

int options)

;返回值:

1.成功後,返回狀態已更改的子程序的id

2.如果指定了wnohang並且存在由pid指定的乙個或多個子程序,但不存在尚未更改的狀態,則返回0

3.出錯時,返回-

1引數pid:

pid <-1

,表示等待任何程序組id等於pid的絕對值的子程序

pid =-1

,表示等待任何子程序

pid =

0,表示等待任何程序組id與呼叫程序的id相等的子程序

pid >

0,表示等待程序id等於pid值的子程序

status:

wifexited

(status)

: 如果子程序正常終止,則返回true

(檢視程序是否是正常退出)

wexitstatus

(status)

: 返回子程序的退出狀態.

僅當wifexited返回true時,提取子程序退出碼(檢視程序的退出碼)

options:

0: 則表示預設阻塞等待;

wnohang: 非阻塞等待,若pid指定的子程序沒有結束,則waitpid

()函式立即返回0

若正常結束,則返回該子程序的id

呼叫wait(&status)等效於:

waitpid(-1, &status, 0);
如果子程序已經退出, 呼叫wait( )/waitpid( )時, wait( )/waitpid( )會立即返回, 並且釋放資源, 獲得子程序退出資訊

如果在任意時刻呼叫wait( )/waitpid( ), 子程序存在且正常執行, 則程序可能阻塞

如果不存在該子程序, 則立即出錯返回

獲取子程序status

wait( )和waitpid( ), 都有乙個status引數, 該引數是乙個輸出型引數

如果傳遞null表示不關心子程序的退出狀態資訊

否則, 作業系統會根據該引數, 將子程序的退出資訊反饋給父程序

子程序退出的返回值只使用了1個位元組儲存, 並且通過wait/waitpid函式的status返回給使用者

這1個位元組的返回值, 在status四個位元組中存放的時候是存放在低16位中的高8位

獲取方式: (status>>8) & 0xff

而低8位儲存了一些特殊的資料 :

低8位中的高1位—core dump標誌, 核心轉儲, 程式異常退出時, 儲存程式的執行資訊, 便於事後除錯

低8位中的低7位— 程式異常退出訊號值, 通知程序發生了某個事件, 中斷程序當前的操作, 去處理這個事件, 獲取方式:status & 0x7f

低七位中的儲存異常退出訊號值若為0, 表示沒有異常訊號, 則表示程式正常退出, 否則表示程式異常退出, 返回值將不具有判斷意義

作業系統中的訊號體現實際上就是乙個數字, 某個數字表示某個異常事件, 程式因為異常退出的時候, 則會將這個異常退出事件的訊號值放到低7位中

我們如何讓子程序完成其他事情???

可以通過fork建立子程序的返回值進行**分流, 例如:

if

(fork()

==0)

但是這種方式存在缺陷: 程式的耦合度非常強, 因為所有功能**都是在當前程式中編寫的. 如果想要改變子程序的功能處理流程, 需要修改整個程式**, 然後重新進行編譯, 這樣一來, 程式就會變得非常大

這樣程式替換的優點就體現出來了~~

替換原理

替換乙個程序正在排程的程式資訊, 將另乙個程式載入到記憶體中, 然後讓原有的pcb不再排程原程式, 而去排程這個新程式. 本質來說就是替換pcb在記憶體中對應的**和資料(載入另乙個程式到記憶體中, 然後更新頁表資訊, 初始化虛擬位址空間), 程式替換之後, 當前程序執行完替換後的程式就會退出, 並不會執行原先的程式

用fork建立子程序後執行的是和父程序相同的程式(但有可能執行不同的**分支), 子程序往往要呼叫一種exec函式以執行另乙個程式. 當程序呼叫一種exec函式時, 該程序的使用者空間**和資料完全被新程式替換, pcb將開始排程執行新程式執行

呼叫exec並不建立新程序, 所以呼叫exec前後該程序的id並未改變

替換函式:

exec函式族 —實現程序的程式替換

#include

extern

char

**environ;

intexecl

(const

char

*path,

const

char

*arg,..

.);path是帶有路徑的新程式名稱,就是使用這個程式替換程序正在排程執行的程式

arg將新程式的執行引數,通過不定參的形式傳遞進入新的程式,以null作為結尾

intexeclp

(const

char

*file,

const

char

*arg,..

.);int

execle

(const

char

*path,

const

char

*arg ,..

.,char

*const envp)

;int

execv

(const

char

*path,

char

*const ar**)

;int

execvp

(const

char

*file,

char

*const ar**)

;以上都是庫函式

這些函式如果呼叫成功則載入新的程式從啟動**開始執行,不再返回

如果呼叫出錯則返回-

1,所以exec函式只有出錯的返回值而沒有成功的返回值

int execve (

const

char

*filename,

char

*const ar** ,

char

*const envp)

事實上,只有execve是真正的系統呼叫,其它五個函式最終都呼叫execve

所以execve在man手冊第2節,其它函式在man手冊第3節

l和v的區別: 在於程式執行引數的賦予方式不同, l通過不定參完成, v通過字串指標陣列進行賦予

有沒有p的區別: 在於第乙個引數指定新程式的時候, 是否需要帶路徑, 有p則可以不用帶路徑, 缺省會去path環境變數指定的路徑下查詢

有沒有e的區別: 在於這個程序的環境變數是否需要重新初始化, 有e則表示初始化, 若沒有e則表示使用預設的環境變數

l

(list)

: 表示引數採用列表

v(vector)

: 引數用陣列

p(path)

: 有p自動搜尋環境變數path

e(env)

: 表示自己維護環境變數

Linux程序控制 程序終止 程序等待

目錄 程序終止 程序中退出的方式 void exit int status 與void exit int status 的不同 程序等待 pid t wait int status void waitpid pid t,int status,int options 阻塞與非阻塞 status 判斷程...

linux 程序控制2

在程序控制的章節我們講解了我們的程序建立,這章節對程序控制進行補充,在我們建立乙個程序之後我們避免不了我們去終止我們的程序。終止場景 終止方式 include void exit int status include void exit int status 雖然兩個函式都是可以讓程序終止的,但是兩...

Linux程序控制(建立 等待 終止)

一 linux程序建立 1.1 fork函式 在linux中fork函式是乙個非常重要的函式,它從已存在程序中建立了乙個新程序。新程序為子程序,而原程序為父程序 include pid t fork void 返回值 自程序中返回0,父程序返回子程序id,出錯返回 1 程序呼叫fork,當控制轉移到...