LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   regarding fork() multiple process (https://www.linuxquestions.org/questions/linux-newbie-8/regarding-fork-multiple-process-895073/)

silentkill89 08-02-2011 07:09 AM

regarding fork() multiple process
 
stil a newbie,trying to fork multiple child but the program does not go as i want...
My code :
Code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


int main()
{
pid_t pid[3];
int i;
 
for(i = 0; i < 3; i++)
{
pid[i]=fork();
if (pid[i] < 0)
{                                    /* Error Message */
printf("Child not created.\n");

}else if (pid[i] == 0)
{
printf("I am child %d,my pid %d,my parent's pid is %d\n",i, getpid(),getppid());

}else{
printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getppid(),i,getpid());

}
}
}

the output i wan is lik
Parent, my pid is 6461: Spawned child #1 whose pid is 6462
Parent, my pid is 6461: Spawned child #2 whose pid is 6463
I am child #1, my pid is 6462; my parent's pid is 6461
I am child #2, my pid is 6463; my parent's pid is 6461
I am child #3, my pid is 6464; my parent's pid is 6461
Parent, my pid is 6461: Spawned child #3 whose pid is 6464

but my output runs lik
Parent,my pid is 1907:Spawned child 0 whose pid is 2910
I am child 0,my pid 2911,my parent's pid is 2910
Parent,my pid is 1907:Spawned child 1 whose pid is 2910
Parent,my pid is 2910:Spawned child 1 whose pid is 2911
Parent,my pid is 1907:Spawned child 2 whose pid is 2910
Parent,my pid is 2910:Spawned child 2 whose pid is 2911
I am child 1,my pid 2913,my parent's pid is 1
Parent,my pid is 1:Spawned child 2 whose pid is 2913
sharina@ubuntu:~$ I am child 2,my pid 2916,my parent's pid is 1
I am child 2,my pid 2915,my parent's pid is 1
I am child 2,my pid 2914,my parent's pid is 1
I am child 1,my pid 2912,my parent's pid is 1
Parent,my pid is 1:Spawned child 2 whose pid is 2912
I am child 2,my pid 2917,my parent's pid is 1

can anyone point out the logic?
thx in advance..

johnsfine 08-02-2011 07:37 AM

Quote:

Originally Posted by silentkill89 (Post 4431559)
stil a newbie

Next time indent the code you post to make it more readable and spell out more of the words in your question to make it more readable.

We are able to read stil, wan, lik, and thx. But that style is discouraged here and next time might result in significantly delaying the useful answers.

This time, your main bug seems to be that you didn't put in a break statement after printing that the code is executing in the child.

The output you say you want seems to assume that only the original parent will continue through the loop forking more children. But as you coded it, each process (parent or child) independently continues through the loop.

But you also have several errors in the values you are printing and/or misunderstandings of the meanings of getpid() and getppid(). For example:
Quote:

printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getppid(),i,getpid());
getpid and getppid are always from the point of view of the code that is executing (not from the point of view of some fork it might have recently executed). So in that code you say "my pid is" getppid(), but that is the pid of the current process's parent. The current process is the parent side of the fork you are reporting, so its parent is the grandparent from the point of view of the fork.

Then you say "Spawned child" i, but i is 0 to 2 representing positions in the pid[] array, and you say you want 1 based reporting, which would be "Spawned child" i+1.

Then you say "whose pid is" getpid() but that is the current process pid, which is the parent from the point of view of the last fork. You should have "whose pid is" pid[i]

silentkill89 08-02-2011 07:42 AM

sory...my bad,1st time posting this forum. i will make it more readable next time. May i know how to exit the condition? i know is using exit(-1) or exit(1), but i tried before and when i compile it gets an error of using the exit() status.sorry im still a newbie..

johnsfine 08-02-2011 07:55 AM

Quote:

Originally Posted by silentkill89 (Post 4431585)
May i know how to exit the condition? i know is using exit(-1) or exit(1), but i tried before and when i compile it gets an error of using the exit() status.

I would have used a break instruction (as I suggested above) to exit the loop after printing the child message. Since the loop is the whole program, exiting the loop is equal to exiting the program.

But if you prefer to use the exit() function, that is also good.

exit() is declared in stdlib.h, so if you want to use exit() you need
#include <stdlib.h>

Corrected code (using break) is
Code:

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

int main()
{
  pid_t pid[3];
  int i;
 
  for(i = 0; i < 3; i++)
  {
      pid[i]=fork();
      if (pid[i] < 0)
      {                                    /* Error Message */
        printf("Child not created.\n");
      }else if (pid[i] == 0)
      {
        printf("I am child %d,my pid %d,my parent's pid is %d\n",i+1, getpid(),getppid());
        break;
      }else{
        printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getpid(),i+1,pid[i]);
      }
  }
}


silentkill89 08-02-2011 10:41 AM

thanks to you johnsfine, somehow i managed i get some idea, now i understand much about the logic. According the code,I dun understand this part
Code:

printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getpid(),i+1,pid[i]);
the first %d, aren't we suppose to put get parent system call,which is getppid()? I though should have called parent pid, kindly explain the logic flow. Thanks in advanced.

silentkill89 08-02-2011 11:46 AM

alright, after been thinking awhile, I finally how it works, thanks johnfine. Now I know parent can only call getpid() because it stand for the process id itself instead of parent,because parent only have 1, however child has a parent pid and its own pid, so 2 system call. Thousand thanks^^

johnsfine 08-02-2011 11:47 AM

Quote:

Originally Posted by johnsfine (Post 4431580)
getpid and getppid are always from the point of view of the code that is executing (not from the point of view of some fork it might have recently executed). So in that code you say "my pid is" getppid(), but that is the pid of the current process's parent. The current process is the parent side of the fork you are reporting, so its parent is the grandparent from the point of view of the fork.

Quote:

Originally Posted by silentkill89 (Post 4431767)
According the code,I dun understand this part
Code:

printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getpid(),i+1,pid[i]);
the first %d, aren't we suppose to put get parent system call,which is getppid()? I though should have called parent pid, kindly explain the logic flow.

I don't have any better explanation than the one I already gave above.

silentkill89 08-02-2011 12:04 PM

OK.But I got 1 last problem, the output show
Code:

Parent,my pid is 8602:Spawned child 1 whose pid is 8603
I am child 1,my pid 8603,my parent's pid is 8602
Parent,my pid is 8602:Spawned child 2 whose pid is 8604
Parent,my pid is 8602:Spawned child 3 whose pid is 8605
I am child 2,my pid 8604,my parent's pid is 8602
I am child 3,my pid 8605,my parent's pid is 1

All works fine except the last line
Code:

I am child 3,my pid 8605,my parent's pid is 1
the parent's pid suppose to be 8602 instead 1. Any idea?

GazL 08-02-2011 01:28 PM

Quote:

Originally Posted by silentkill89 (Post 4431826)
the parent's pid suppose to be 8602 instead 1. Any idea?

My guess is that the parent process is ending before the 3rd child gets up and running, by which time the child has been inherited by init (PID 1)

Have a read of the man-page for wait() There's an example program at the end which should help.

johnsfine 08-02-2011 01:30 PM

Quote:

Originally Posted by silentkill89 (Post 4431826)
All works fine except the last line
Code:

I am child 3,my pid 8605,my parent's pid is 1
the parent's pid suppose to be 8602 instead 1. Any idea?

Easy to understand, a bit harder to fix well.

You get that behavior because parent process exits before the child process asks the system for the identity of its parent.

getppid() is giving you the pid of the parent at the moment getppid() is called, not the original parent. If the original parent is gone then getppid() returns 1.

silentkill89 08-03-2011 12:01 AM

Ok, i understand what's the problem. But when i change
Code:

i <= 3
it will ends up in an unstoppable loop, so possibly I will try to put a wait() system call inside to see how it goes, or is there anyway to issue the parent process to exit after it's pid display or just only using wait()?

GazL 08-03-2011 07:27 AM

Changing the conditional from '<' to '<=' really doesn't have any relevance to the problem you're seeing.

You can change your approach and pass the parents pid across the fork() instead of letting each child call getppid()
Code:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main()
{
  pid_t pid[3];
  pid_t forkedby, mypid;
  int i;
 
  forkedby = mypid = getpid();
   
  for(i = 0; i < 3; i++)
  {
      pid[i]=fork();
      if (pid[i] < 0)
      {                                    /* Error Message */
        printf("Child not created.\n");
      }else if (pid[i] == 0)
      {
        mypid=getpid();
        printf("I am child %d,my pid %d,my parent's pid is %d\n", i+1, mypid, forkedby);
        break;
      }else{     
        printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n", mypid, i+1, pid[i]);
      }
  }
  return 0;
}

or you can keep the parent alive and let it manage its children with wait():
Code:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define NUM_CHILDREN 3

int main()
{
  pid_t pid[NUM_CHILDREN];
  pid_t wait_pid;
  int i;
  int status;
 
  for(i = 0; i < NUM_CHILDREN ; i++)
  {
      pid[i]=fork();
      if (pid[i] < 0)
      {                                    /* Error Message */
        printf("Child not created.\n");
      }else if (pid[i] == 0)
      {
        printf("I am child %d,my pid %d,my parent's pid is %d\n",i+1, getpid(),getppid());
        break;
      }else{
        printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getpid(),i+1,pid[i]);
        if ( i == (NUM_CHILDREN - 1) ) {
          for ( errno=0 , wait_pid=0 ; wait_pid != -1 ; errno=0 ) {
            wait_pid=wait(&status);
            if (errno == ECHILD)
              printf("Parent, all children have finished.\n");
            else if ( WIFEXITED(status) )
              printf("Parent, child %d has exited...\n", wait_pid);
          }
        }
      }
  }

  return 0;
}

... which is obviously more involved.

silentkill89 08-03-2011 07:46 AM

Quote:

Originally Posted by GazL (Post 4432557)
Changing the conditional from '<' to '<=' really doesn't have any relevance to the problem you're seeing.

You can change your approach and pass the parents pid across the fork() instead of letting each child call getppid()
Code:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main()
{
  pid_t pid[3];
  pid_t forkedby, mypid;
  int i;
 
  forkedby = mypid = getpid();

   
  for(i = 0; i < 3; i++)
  {
      pid[i]=fork();
      if (pid[i] < 0)
      {                                    /* Error Message */
        printf("Child not created.\n");
      }else if (pid[i] == 0)
      {
        mypid=getpid();
        printf("I am child %d,my pid %d,my parent's pid is %d\n", i+1, mypid, forkedby);
        break;
      }else{     
        printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n", mypid, i+1, pid[i]);
      }
  }
  return 0;
}

or you can keep the parent alive and let it manage its children with wait():
Code:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define NUM_CHILDREN 3

int main()
{
  pid_t pid[NUM_CHILDREN];
  pid_t wait_pid;
  int i;
  int status;
 
  for(i = 0; i < NUM_CHILDREN ; i++)
  {
      pid[i]=fork();
      if (pid[i] < 0)
      {                                    /* Error Message */
        printf("Child not created.\n");
      }else if (pid[i] == 0)
      {
        printf("I am child %d,my pid %d,my parent's pid is %d\n",i+1, getpid(),getppid());
        break;
      }else{
        printf("Parent,my pid is %d:Spawned child %d whose pid is %d\n",getpid(),i+1,pid[i]);
        if ( i == (NUM_CHILDREN - 1) ) {
          for ( errno=0 , wait_pid=0 ; wait_pid != -1 ; errno=0 ) {
            wait_pid=wait(&status);
            if (errno == ECHILD)
              printf("Parent, all children have finished.\n");
            else if ( WIFEXITED(status) )
              printf("Parent, child %d has exited...\n", wait_pid);
          }
        }
      }
  }

  return 0;
}

... which is obviously more involved.

wow...i guess first idea make more simple and directive. However the second idea just having parent to finish their job,which is more efficient. Thanks in advance GAZL. By the way, at the 2nd idea where
Code:

else if ( WIFEXITED(status) )
statement, WIFEXITED is a reserved word for <sys/wait.h> library or just normal initialization?

GazL 08-03-2011 07:52 AM

It's a macro from wait.h provided to be used with the wait() call. It's all on the man-page.

johnsfine 08-03-2011 07:55 AM

Quote:

Originally Posted by silentkill89 (Post 4432570)
WIFEXITED is a reserved word for <sys/wait.h> library or just normal initialization?

You could have gotten the answer to that faster with google than by asking in the forum.

google WIFEXITED and many of the hits are online copies of
man 3 wait
such as the one at:
http://linux.die.net/man/3/wait

In that man page you can find the description of WIFEXITED

Code:

the following macros, which are defined in <sys/wait.h>
...
WIFEXITED(stat_val)

    Evaluates to a non-zero value if status was returned for a child process that terminated normally.

Quote:

Originally Posted by GazL (Post 4431879)
Have a read of the man-page for wait()

The OP might not have known that the command to get that man page is
man 3 wait
Or the OP might not have that man page installed on his Linux system (I don't have it on any of my Linux systems. Not sure why. Most man 3 pages I've tried are there.)

When missing a man page, google (to find an online copy of the man page) is usually faster than finding out what package you need to install.


All times are GMT -5. The time now is 12:17 AM.