Linux系統程式設計(二)
複習檔案描述符(指向結構體的指標)
exec函式族
fork建立子程序後執行的是和父程序相同的程式(但是有可能執行不同的程式碼分支)子程序往往要呼叫一種exec函式以執行另外一個程式,當程序呼叫一種exec函式時,該程序的使用者空間程式碼和資料完全被新程式替代,從新程式的啟動例程開始執行,呼叫exec並不建立新的程序,所以呼叫exec前後程序的ID並未改變。
重點掌握
execlp函式
載入一個程序,藉助PATH環境變數
int execlp(const char *file, const char *arg, …);
引數1 要載入的程式的名稱該函式要配合PATH環境變數來使用,當PATH中所以目錄搜尋後沒有引數1時則出錯返回
該函式通常用來呼叫系統程式如:ls date cp cat 等命令
#include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 int main(void)
5 {
6 pid_t pid;
7 pid = fork();
8 if(pid == -1){
9 perror("fork error");
10 exit(1);
11 }else if(pid > 0)
12 {
13 sleep(1 );
14 printf("parent\n");
15 }else{
16 execlp("ls","ls","-l",NULL);
17 /*函式使用的引數幾點注意①第一個引數是可執行程式名 ②必須以NULL結尾③對第二個引數沒有要求*/
18 }
19 return 0;
20 }
補充 命令列引數
描述命令列引數的個數 argc
命令列引數的陣列 argv
execl 函式
載入一個程序 通過路徑+程式名
execl("/bin/ls","ls","-l",NULL);
execv函式
/*其它部分相同*/
char *argv[] = {"ls","ls","-l",NULL};
execv("/bin/ls",argv);
練習:將當前系統中的資訊列印到檔案中 主要open dup2 execlp 函式
dup2函式:完成檔案描述符的拷貝
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int fd;
fd = open("ps.out",O_WRONLY|O_CREAT|O_TRUNL,0644);
if(fd < 0){
perror("open ps.out error");
exit(1);
}
dup2(fd, STDOUT_FILENO); //dup2(3,1) fd stdout
execlp("ps","ps","ax",NULL);
perror("exec error");
exit(1); //出錯處理
return 0;
}
總結 exec函式一旦呼叫成功即執行新的程式不返回,只有失敗才返回-1所以通常我們直接在exec函式呼叫後直接呼叫perror()和exit()無需if判斷
回收子程序
孤兒程序
父程序先於子程序結束,則子程序成為孤兒程序,子程序的父程序成為init程序 稱為init程序領養孤兒程序
殭屍程序
程序終止,父程序尚未回收,子程序殘留資源(PCB)存放在核心中,變成殭屍程序。
Wait函式
三個功能:
①阻塞等待子程序退出
②回收子程序殘留資源
③獲取子程序結束狀態
pid_t wait(int *status);注意是傳出引數,需要定義一個變數接受它。成功:清理掉子程序的ID,失敗:-1
可藉助wait函式傳出引數status來儲存程序的退出狀態。藉助巨集函式來進一步來判斷程序終止的具體原因
1 WIFEXITED( status) 為非0 程序正常結束
WEXITSTATUS(status) 如果上巨集為真,實用此巨集可以獲取程序退出狀態(exit的值)
2 WIFSIGMALED(status) 非0 程序異常終止
WTERMSIG(status) 如果上巨集為真,實用巨集取得使程序終止的那個訊號的編碼
//主要部分
if( WIFEXITED( status)){
printf("child exit with %d\n",WEXITSTATUS(status);
}if(WIFSIGMALED(status)){
printf("child killed by %d\n",WTERMSIG(status));
}
回收多個子程序用迴圈
一次wait或waitpid呼叫只能清理一個子程序,清理多個子程序應使用迴圈
while(wait(NULL))
;
//或者
while(waitpid(-1,NULL,0)); // 參3 為0時阻塞狀態
不同點 第三個引數 WNOHANG 會探測子程序是否結束,為非阻塞狀態,輪循結構使用do while
int n = 5 //子程序個數
pid_t wpid;
do{
wpid = waitpid(-1,NULL,0);
if(wpid > 0){
n--;
}
sleep(1);
}while(n > 0);