![](/img/trans.png)
[英]Unexpected behavior when printf is used after fork() and the parent is on wait()
[英]Printf and fork: wrong ordering, even when wait(NULL) is used
因此,我正在創建一個非常簡單的外殼包裝程序。 主進程使用readline讀取一行,然后將其解析為char * [],然后由execvp處理。 Fork用於確保execvp運行后程序繼續運行。 如果命令以&結尾,則母進程在繼續之前不會等待派生完成。 如果結尾沒有&,則母親等待孩子完成。
一些代碼:主要和接受輸入功能
int main(){
//Welcome message
printf("Welcome to Bourne Shell Wrapper! Enter commands to run them, use ctrl+d to exit\n");
while(1){
//Prefering the complex readline over the easier scanf because of many functions that scanf does not offer.
char* line = readline("shw> ");
if (line == NULL) return 0;
struct Command command = parseInput(line);
if (command.params != NULL){
if (!runCommand(command)) return 1;
}
}
結構命令:
struct Command{
char async;
char** params;
};
運行命令的函數:
int runCommand(struct Command command){
//Fork, let the child run the command and the parent wait for the child to finish before returning
//The child has 0 as childPid, the mother has another positive value. Thats how we seperate them
pid_t childPid = fork();
if (childPid == -1){
printf("Failed to create child\n");
return 0;
} else if (childPid == 0){
if (execvp(command.params[0], command.params) == -1){
fprintf(stderr,"%s: ",strerror(errno));
printCommand(command);
}
return 1;
} else {
if (!command.async){
//This way the mother will wait until all her childeren are done before continuing
wait(NULL);
} else {
}
return 1;
}
}
所以,這就是問題所在。 當您不想異步時,這些東西就可以了:
Welcome to Bourne Shell Wrapper! Enter commands to run them, use ctrl+d to exit
shw> ls
debug Makefile obj release rpi-release src
shw>
正如預期的那樣:母進程等待直到子進程返回,然后再次打印。 然后:
shw> ls &
shw> debug Makefile obj release rpi-release src
半預期的:由於父級繼續運行而無需等待該過程,因此在ls輸出之前會打印shw。 但是之后:
ls
shw> debug Makefile obj release rpi-release src
奇怪的! 父級應該等到子進程完成后才能重新打印shw>,但是它會在子級之前打印。
我不知道為什么會這樣。 有人可以指出我正確的方向嗎? 作為記錄,無需使用&,一切正常。
您的評論說:
the mother will wait until all her childeren are done before continuing
但這不是事實。 wait()
等待一個孩子,無論哪個孩子先完成(包括一個在wait()
調用之前完成的孩子wait()
。
總結一下:執行異步命令時,您不必等待子進程完成; 當執行同步命令時,您等待一個孩子完成。 總而言之,您的wait()
少於創建的子級。
當您調用wait()
,您知道您正在等待一個特定的孩子,但是您沒有告訴您wait
它,因此它將只等待第一個完成的孩子。 最終等待的孩子可能是先前發起的異步孩子,該孩子已經完成但狀態尚未獲得。
因此,這里有一個重要原則: 每個孩子都必須在某個時候獲得收成。 如果您wait(2)
每個孩子wait(2)
,您將積累僵屍進程:實際上已經死了但仍在OS進程列表中的進程,因為它們的狀態尚未恢復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.