wait命令不会等待子进程完成c cpp c ++

时间:2010-10-13 22:38:36

标签: c++ c fork parent-child wait

我正在尝试编写一个创建子进程的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()命令中等待,并且子进程将打印出“Child done sleeping ...”然后完成,然后父进程将打印出“Parent:running ...”

我做错了什么!

谢谢!

更新:程序的完整输出是:

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

4 个答案:

答案 0 :(得分:3)

我发现了四个问题:

1)execlp()失败:execlp()(或任何exec系列函数)如果成功则完全替换当前正在运行的过程映像 - 它不会返回,除非出了点问题。但是你看到了“Child:Done sleeping,return”的消息,所以它不可能成功。 (在您的示例中,我猜这可能是因为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
$

答案 1 :(得分:0)

你为什么要这样做

wait((void*)pid)

等待指针指向状态

   #include <sys/types.h>
   #include <sys/wait.h>

   pid_t wait(int *status);

你几乎可以通过不可写的地址。测试等待重新编码,我打赌是抱怨很大的时间;

混合printf和couts是一种让自己迷惑的方法,他们的缓冲/冲洗方案可能会有所不同

答案 2 :(得分:0)

wait((void*)pid);

你不应该把事情变成无效*只是为了让编译器停止抱怨。 :)

看起来你可能想要 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”,子进程基本上会立即退出。这将取消阻止父进程并允许它执行。

答案 3 :(得分:0)

您通常会打开结果以允许错误案例

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