views:

1128

answers:

5

Hi all, I am kind of newbie on C++, and working on a simple program on Linux which is supposed to invoke another program in the same directory and get the output of the invoked program without showing output of the invoked program on console. This is the code snippet that I am working on:

    pid_t pid;
    cout<<"General sentance:"<<endl<<sentence<<endl;
    cout<<"==============================="<<endl;
    //int i=system("./Satzoo");
    if(pid=fork()<0)
     cout<<"Process could not be created..."<<endl;
    else
    {
     cout<<pid<<endl;
     execv("./Satzoo",NULL);
    }
    cout<<"General sentance:"<<endl<<sentence<<endl;
    cout<<"==============================="<<endl;

One of the problem I encounter is that I am able to print the first two lines on console but I cant print the last two lines. I think the program stops working when I invoke the Satzoo program. Another thing is that this code invokes Satzoo program twice, I dont know why? I can see the output on screen twice. On the other hand if I use system() instead of execv(), then the Satzoo works only once.

I haven't figured out how to read the output of Satzoo in my program.

Any help is appreciated.

Thanks

+3  A: 

The fork() function clones the current process and returns different values in each process. In the "parent" process, it returns the pid of the child. In the child process, it returns zero. So you would normally invoke it using a model like this:

if (fork() > 0) {
    cout << "in parent" << endl;
} else {
    cout << "in child" << endl;
    exit(0);
}

I have omitted error handling in the above.

In your example, both of the above code paths (both parent and child) fall into the else clause of your call to fork(), causing both of them to execv("./Satzoo"). That is why your program runs twice, and why you never reach the statements beyond that.

Instead of using fork() and doing everything manually (properly managing process execution is a fair amount of work), you may be interested in using the popen() function instead:

FILE *in = popen("./Satzoo", "r");
// use "in" like a normal stdio FILE to read the output of Satzoo
pclose(in);
Greg Hewgill
I agree with you; but if you're just learning then it pays to learn the fundamental concepts and issues.
BobbyShaftoe
A: 

There are three return value tests you want with fork

  1. 0: you are the child
  2. -1: error
  3. other: you are the parent

You ran the other program from both the child and the parent...

DigitalRoss
+7  A: 

You aren't distinguisng between the child and the parent process after the call to fork(). So both the child and the parent run execv() and thus their respective process images are replaced.

You want something more like:

pid_t pid;
printf("before fork\n");

if((pid = fork()) < 0)
{
  printf("an error occurred while forking\n");
}
else if(pid == 0)
{
  /* this is the child */
  printf("the child's pid is: %d\n", getpid());
  execv("./Satzoo",NULL);
  printf("if this line is printed then execv failed\n");
}
else
{
  /* this is the parent */
  printf("parent continues execution\n");
}
BobbyShaftoe
Hi, Thanks for the answer. Now, I sort of understand the functionality of fork() but still dont understand why would I want to create a clone of the same process. Maybe I should dig more into it. Another thing that I dont get is that if the clone process is identical with the parent, why the last two lines are not printed on the screen since both the parent and the child executes the same code.Thanks again...
Ahmet Keskin
@Ahmet Keskin: The simple answer is that `execv()` never returns - it *replaces* the current process with a new one.
Greg Hewgill
@Ahmet Keskin, ok the fork() creates a copy of a process. The process created from a fork is called the "child" process and the original process, the parent. The return value of fork() is different depending on whether you are the parent or child. If you are the child, then fork() returns 0 otherwise it returns the pid of the child that was created. Now, when the child calls execv(), that function calls a system call that ultimately replaces almost everything in the process that executed it, with the one you are trying to execute (only certain resources are kept, but the program instructions
BobbyShaftoe
are not kept. So, you probably use fork() all the time without realizing it. This is how a typical shell like bash works. When you tell bash to run some program, it will fork() a child process and then call an exec function. So, you'll see that the shell is the parent of the program you start. There are other reasons to fork that don't include calling an exec function. You might have a server that forks a child process for every incoming connection. These are just the basics though.
BobbyShaftoe
Thanks, that concludes my problem :)
Ahmet Keskin
@Ahmet Keskin: Does it? Just correctly calling `fork()` won't help you get the output of the second program into the first one, in fact without further adjustments the output of "Satzoo" will go to the same place as the first program's output.
Greg Hewgill
+2  A: 

From the fork() manpage:

RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to the parent process, no child process shall be created, and errno shall be set to indicate the error.

You check to make sure it succeeds, but not whether the pid indicates we're in the child or the parent. Thus, both the child and the parent do the same thing twice, which means that your program gets executed twice and the ending text is never printed. You need to check the return value of fork() more than just once.

Chris Lutz
+1  A: 

exec - The exec() family of functions replaces the current process image with a new process image.

system - Blocks on execution of the command. Execution of the calling program continues after the system command returns

terry
@terry, welcome to SO!
BobbyShaftoe