[英]wait command wont wait for child process to finish c cpp c++
我正在嘗試編寫一個c ++程序,該程序創建一個子進程,運行一個命令,並將輸出通過管道傳遞回父級正在運行的命令的輸入。
我讓父母執行wait(NULL)或wait((void *)pid)命令,但它不等待。
這是代碼:
#include <string.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char * argv[])
{
char* commands[strlen(argv[1])];
char *command = NULL;
command = strtok(argv[1],"|");
int i = 0;
while(command != NULL)
{
commands[i] = command;
i++;
command = strtok(NULL,"|");
}
int numberOfCommands = i;
pid_t pid;
int pfd[2];
char* prgname = NULL;
if(pipe(pfd) == -1)
{
perror("error on pipe call");
return(1);
}
for(int j = 0;j<numberOfCommands;j++)
{
cout<<commands[j]<<endl;
}
pid = fork();
if(pid == 0){//child process
printf("Child: My PID = %d\n", getpid());
printf("Child: Running...\n");
close(pfd[0]); //close read end of pipe
dup2(pfd[1],1);//connect the pipes
close(pfd[1]);//close extra file descriptors
prgname = commands[0];//first command
cout<<"child starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the program
**printf("Child: Done sleeping, returning.\n");**
}
else
{
printf("Parent: My PID = %d\n", getpid());
**wait((void*)pid); //also tried wait(NULL); same effect
printf("Parent: Running...\n");**
close(pfd[1]); //close the write end of the pipe
dup2(pfd[0],0);//connect the pipes
close(pfd[0]); //close extra file descriptor
prgname = commands[1];//now run the second command
cout<<"parent starting command: "<<prgname<<endl;
execlp(prgname, prgname, 0);//Load the programm
}
cout<<"all done"<<endl;
return 0;
}
不要采用粗體字。 我希望父進程等待wait()命令,然后子進程將打印出“子進程正在休眠...”,然后完成操作,然后父進程將打印出“父進程:正在運行...”。
我究竟做錯了什么!
謝謝!
更新:程序的完整輸出為:
dmegs
more
Child: My PID = 30070
Child: Running...
Parent: My PID = 30066
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done
我看到四個問題:
1) execlp()
失敗:如果成功, execlp()
(或任何exec
系列功能)將完全替換當前正在運行的進程映像-除非出現問題,否則它不會返回。 但是您看到的是“孩子:睡着了,回去了”的消息,所以它不可能成功。 (在您的示例中,我想這可能是因為dmegs
應該是dmesg
。)
2) printf()
和cout
輸出緩沖意味着無法保證您按發生的順序獲得輸出。 如果要通過打印輸出進行調試,最好打印到(默認情況下)沒有緩沖的stderr
(例如,使用fprintf(stderr, ...)
)。
3)如其他人所述, wait((void *)pid)
是錯誤的。 wait(NULL)
或waitpid(pid, NULL, 0)
。
4)這個問題是否與平台相關,但是... execlp()
的終止空指針參數應顯式寫為(char *)0
而不是0
,以確保將其傳遞為指針而不是整數。 通常,在C語言中,指針上下文中的0
根據定義是一個空指針,但是當將參數傳遞給具有可變數量參數的函數時,編譯器沒有足夠的信息來知道您正在嘗試在指針上下文中使用它,因此,除非您明確將其強制轉換,否則它將作為整數傳遞。 在指針和整數大小不同的平台上,這可能會給您帶來麻煩。
因此我認為wait()
正在工作,子進程實際上並未運行您想要的命令,並且由於緩沖,父子進程的輸出變得混亂。
這是代碼的略微修改版本,它不使用任何C ++,切掉命令處理內容,而只是將sleep 5
的輸出通過管道傳遞給cat
(這毫無意義,因為sleep
不會生成任何輸出,但延遲對於了解發生的情況很有用):
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
int pfd[2];
if(pipe(pfd) == -1)
{
perror("error on pipe call");
return(1);
}
pid = fork();
if(pid == 0){//child process
fprintf(stderr, "Child: My PID = %d\n", getpid());
fprintf(stderr, "Child: Running...\n");
close(pfd[0]); //close read end of pipe
dup2(pfd[1],1);//connect the pipes
close(pfd[1]);//close extra file descriptors
fprintf(stderr, "child starting command: sleep 5\n");
execlp("sleep", "sleep", "5", (char *)0);//Load the program
fprintf(stderr, "child: execlp failed\n");
}
else
{
fprintf(stderr,"Parent: My PID = %d\n", getpid());
wait(NULL);
fprintf(stderr,"Parent: Running...\n");
close(pfd[1]); //close the write end of the pipe
dup2(pfd[0],0);//connect the pipes
close(pfd[0]); //close extra file descriptor
fprintf(stderr,"parent starting command: cat\n");
execlp("cat", "cat", (char *)0);//Load the programm
}
fprintf(stderr,"all done\n");
return 0;
}
輸出:
$ gcc -Wall -o wait wait.c
$ ./wait
Child: My PID = 27846
Child: Running...
child starting command: sleep 5
Parent: My PID = 27845
(這里有5秒的延遲)
Parent: Running...
parent starting command: cat
$
您通常會打開結果以考慮錯誤情況
pid = fork();
switch( pid ) {
case -1: // parent fail
case 0: // child success
default: // parent success
}
等待您想要使用的特定孩子
waitpid( pid, NULL, 0 );
或等待任何孩子
pid_t child = waitpid( -1, NULL, 0 );
你為什么這么做
wait((void*)pid)
等待將指針指向狀態
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
您幾乎肯定會傳遞不可寫的地址。 測試等待重新編碼,我打賭正在抱怨很多時間;
另外,混合使用printf和cout是一種使自己困惑的方法,它們的緩沖/刷新方案可能不同
wait((void*)pid);
您不應該為了使編譯器停止抱怨而將內容強制轉換為void *。 :)
看來您可能想要waitpid : http : //linux.die.net/man/2/waitpid
更新:
您需要檢查execlp調用是否真正起作用。 相比:
$ ./a.out "dmegs|more"
dmegs
more
Parent: My PID = 20806
Child: My PID = 20807
Child: Running...
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done
有:
$ ./a.out "dmesg|more"
dmesg
more
Parent: My PID = 20876
Child: My PID = 20877
Child: Running...
^C
在第一種情況下,由於execlp找不到“ dmegs”,因此子進程基本上會立即退出。 這將解除對父進程的阻止,並允許其執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.