我們知道, 子程序先退出, 父程序如果不管不顧, 就會導致殭屍程序, 進而造成資源洩漏等嚴重問題
一旦產生殭屍程序, 「殺人不眨眼」的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,當控制轉移到...