1. 程式人生 > >Linux系統程式設計(二)

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);