Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

wait command wont wait for child process to finish c cpp c++

I am trying to write a c++ program that creates a child process, runs a command and pipes the output back to the input of a command the parent is running.

I have the parent execute the wait(NULL) or wait((void*)pid) command but it does not wait.

here is the code:

#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;
}

Take not of the bolded lines. I would expect the parent process to wait at the wait() command and the child would print out "Child done sleeping..." and then finish and then the parent would print out "Parent: running..."

What am I doing wrong!

Thanks!

Update: full output to program is:

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
like image 309
kralco626 Avatar asked Oct 28 '25 23:10

kralco626


1 Answers

I see four problems:

1) execlp() is failing: execlp() (or any of the exec family of functions) completely replaces the currently running process image if successful - it is not expected to return, unless something goes wrong. But you are seeing the "Child: Done sleeping, returning" message, so it cannot have succeeded. (In your example, I would guess that this is probably because dmegs should have been dmesg.)

2) printf() and cout output buffering means that there is no guarantee whatsoever that you are getting the output in the order in which it happens. If you want to debug this by printing output, you would be better off printing to stderr (e.g. with fprintf(stderr, ...)) which is (by default) unbuffered.

3) As noted by others, wait((void *)pid) is wrong. wait(NULL) or waitpid(pid, NULL, 0).

4) Whether this one is a problem or not is platform-dependent, but... the terminating null pointer argument to execlp() should be explicitly written as (char *)0 rather than just 0, to ensure that it is passed as a pointer rather than an integer. In general in C, 0 in a pointer context is by definition a null pointer, but when passing parameters to functions with variable numbers of arguments, the compiler does not have enough information to know that you are trying to use it in a pointer context, and so will pass it as an integer unless you explicitly cast it. This can get you into trouble on platforms where pointers and integers are not the same size.


So I reckon the wait() is working, the child is not actually running the command you want, and the output from parent and child is getting mixed up due to buffering.


Here is a slightly modified version of your code, which doesn't use any C++, cuts out the command handling stuff, and just pipes the output of sleep 5 to cat (which is rather pointless, as sleep doesn't generate any output anyway, but the delay is useful to see what's going on):

#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;
}

Output:

$ gcc -Wall -o wait wait.c
$ ./wait
Child: My PID = 27846
Child: Running...
child starting command: sleep 5
Parent: My PID = 27845

(there is a 5 second delay here)

Parent: Running...
parent starting command: cat
$
like image 117
Matthew Slattery Avatar answered Oct 31 '25 13:10

Matthew Slattery



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!