1.替換原理
????用fork創建子進程后執行的是和父進程相同的程序(但有可能執行不同的代碼分支),子進程往往要調用一種exec函數以執行例外一個程序。當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序替換,從新程序的啟動歷程開始執行。調用exec并不創建新進程,所以調用exec前后該進程的id并未變化
2.實現一個shell
#include<stdio.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>int main()
{char buf[1024] = { 0 };while(1){printf("mysell#");fflush(stdout);size_t s = read( 0, buf, sizeof( buf ) );if(s > 0){buf[s - 1] = '\0';printf("%s\n", buf);}char* start = buf;char* _argv[32];_argv[0] = buf;int i = 1;while(*start){if(*start == ' '){*start = '\0';start ++;_argv[i++] = start;}else{start ++;}}_argv[i] = NULL;pid_t pid;pid = fork();if(pid < 0){perror("fork");exit(1);}if(pid == 0){execvp(_argv[0], _argv);}else if(pid > 0){int st = 0;wait(&st);}}return 0;
}
????????????
3.system(),popen(),fork()三個函數的qubie
????(1)system()函數
#include <stdlib.h>
int system(const char *command);
???? 1)system在執行過程中經理fork -> exec -> wait ,但system在執行過程中會一直等待,直到shell命令執行完后才退出,即system為串行執行
???? 2)system在執行過程中對SIGCHLD、SIGINT、SIGQUIT都做了處理
???? 3)SIGCHLD是子進程退出的時候發給父進程的一個信號,system()中為什么要屏蔽SIGCHLD信號?就是為了system()調用能夠及時的退出并且能夠正確的獲取子進程的退出狀態(成功回收子進程)。
????(2)popen函數
#include <stdio.h>
FILE *popen(const char *command, const char *type);
???? 1)popen函數在執行時無須等待shell執行完才退出,即popen是并行執行
???? 2)popen在執行時對SIGCHLD、SIGINT、SIGQUIT信號不做如何處理,
???? 3)popen創建的子進程如果不執行pclose,popen創建的子進程就會成為僵尸進程
???? 4)popen() 函數用創建管道的方式啟動一個 進程, 并調用 shell. 因為管道是被定義成單向的, 所以 type 參數只能定義成只讀或者只寫, 不能是兩者同時, 結果流也相應的是只讀或者只寫. command 參數是一個字符串指針, 指向的是一個以 null 結束符結尾的字符串, 這個字符串包含一個 shell 命令. 這個命令被送到 /bin/sh 以 -c 參數執行, 即由 shell 來執行. type 參數也是一個指向以 null 結束符結尾的字符串的指針, 這個字符串必須是 ‘r‘ 或者 ‘w’ 來指明是讀還是寫。
???? 5)popen沒有屏蔽SIGCHLD,主要的原因就是popen是”并行”的。如果我們在調用popen的時候屏蔽了SIGCHLD,那么如果在調用popen和pclose之間調用進程又創建了其它的子進程并且調用進程注冊了SIGCHLD信號處理句柄來處理子進程的回收工作(waitpid)那么這個回收工作會一直阻塞到pclose調用。這也意味著如果調用進程在pclose之前執行了一個wait()操作的話就可能獲取到popen創建的子進程的狀態,這樣在調用pclose的時候就會回收(waitpid)子進程失敗,返回-1,同時設置errno為ECHLD,標示pclose無法獲取子進程狀態。
????(3)fork函數
???? fork用來創建一個子進程.
???? 1)系統讓新的進程與舊的進程使用同一個代碼段,因為它們的程序還是相同的,對于數據段和堆棧段,系統則復制一份給新的進程,這樣,父進程的所有數據都可以留給子進程
???? 2)子進程一旦開始運行,雖然它繼承了父進程的一切數據,但實際上數據卻已經分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數據了。而如果兩個進程要共享什么數據的話,就要使用另一套函數(shmget,shmat,shmdt等)來操作。現在,已經是兩個進程了,對于父進程,fork函數返回了子程序的進程號,而對于子程序,fork函數則返回零,這樣,對于程序,只要判斷fork函數的返回值,就知道自己是處于父進程還是子進程中