- 程序建立
- 程序終止
- 程序等待
- 程式替換
程序建立
fork函數
建立一個子程序,父子程序代碼共享,資料獨有
#include <unistd.h>
pid_t fork(void);
傳回值:自程序中傳回0,父程序傳回子程序id.出錯傳回1。
當調用fork函數時,通過使用寫時拷貝技術來拷貝父程序的資訊。
寫時拷貝技術:子程序通過複制父程序的pcb,使得複制程序指向同一塊實體記憶體,同時運作位置,和代碼相同。但又因為程序之間需要獨立性,是以當某一個程序資料發生改變的時候會重新給子程序開辟實體記憶體,将資料拷貝過去。(之是以這樣使用是因為如果資料不修改的話還開辟空間拷貝資料會使效率降低)
這也就是資料獨有的原因。
代碼共享:通過頁表來實作通路控制,使代碼段是隻讀的,不可修改。
vfork函數
建立一個子程序,并且阻塞父程序,直到子程序退出或者程式替換,父程序才繼續運作。
#include <unistd.h>
pid_t vfork(void);
傳回值:自程序中傳回0,父程序傳回子程序id.出錯傳回1。
vfork建立子程序的效率比fork要高,因為vfork所建立的子程序和父程序共用同一個虛拟位址空間。
但也因為這樣,程序之間就不具備獨立性,父子程序不能同時通路代碼段和資料段,是以當子程序運作的時候必須要阻塞父程序,防止産生沖突。
雖然vfork效率高,但是fork因為實作了寫時拷貝技術,效率提高了不少,是以vfork已經很少使用了。
程序終止
在linux下有三種終止程序的方法。
return:
隻能在main函數中使用,退出後重新整理緩沖區
exit:
庫函數調用接口
#include <unistd.h>
void exit(int status);
退出重新整理緩沖區
_exit:
系統函數調用接口
#include <unistd.h>
void _exit(int status);
參數:status 定義了程序的終止狀态,父程序通過wait來擷取該值
退出不重新整理緩沖區
程序等待
之前講過,如果子程序退出時沒有給父程序傳回退出的資訊,父程序就會以為他并沒有退出,是以一直不釋放他的資源,使子程序進入僵屍狀态。
之前的解決方法是退出父程序,但是那個不是一個合理的解決方法,這裡有更好的方法,就是程序等待。
wait
阻塞等待任意一個程序退出,擷取退出子程序的pid,并且釋放子程序資源。
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
傳回值:
成功傳回被等待程序pid,失敗傳回-1。
參數:
輸出型參數,擷取子程序退出狀态,不關心則可以設定為NULL
阻塞:為了完成某個功能發起調用,如果不具備完成功能的條件,則調用不傳回一直等待。
非阻塞:為了完成某個功能發起調用,如果不具備完成功能的條件,則立即報錯傳回
waitpid
可以指定等待一個子程序的退出
#include<sys/wait.h>
pid_ t waitpid(pid_t pid, int *status, int options);
傳回值:
當正常傳回的時候waitpid傳回收集到的子程序的程序ID;
如果設定了選項WNOHANG,而調用中waitpid發現沒有已退出的子程序可收集,則傳回0;
如果調用中出錯,則傳回-1,這時errno會被設定成相應的值以訓示錯誤所在;
參數:
pid:
Pid=-1,等待任一個子程序。與wait等效。
Pid>0.等待其程序ID與pid相等的子程序。
status:
WIFEXITED(status): 若為正常終止子程序傳回的狀态,則為真。(檢視程序是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子程序退出碼。(檢視程序的退出碼)
options:
WNOHANG: 若pid指定的子程序沒有結束,則waitpid()函數傳回0,不予以等待。若正常結束,則傳回該子程序的ID。
程式替換
建立子程序必定是想讓子程序做與父程序不一樣的事情,如果采用判斷pid的方法來進行代碼分流,這樣的程式會非常龐大,是以還有更好的方法,就是程式替換。
程式替換
替換一個程序正在排程的程式資訊(加載另一個程式到記憶體中,讓PCB不在排程原來的程式,排程這個新的程式。隻是改變了映射關系,是以原本的PCB和程式還在 )
exec
#include <unistd.h>`
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg, …,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
乍一看這麼多接口很不容易記,其實是有規律的。
l(list) : 表示參數采用清單
v(vector) : 參數用數組
p(path) : 有p自動搜尋環境變量PATH
e(env) : 有e表示自己維護環境變量