using fork() to make 3 children out of 1 parent in C (not C++)
Solution 1
The parent needs to
- print a message
- call fork three times
- wait for the three children to exit
Each child needs to
- print a message
- exit
So the code is as simple as
int main( void )
{
printf( "[dad] pid %d\n", getpid() );
for ( int i = 0; i < 3; i++ )
if ( fork() == 0 )
{
printf( "[son] pid %d from pid %d\n", getpid(), getppid() );
exit( 0 );
}
for ( int i = 0; i < 3; i++ )
wait( NULL );
}
which generates this output
[dad] pid 1777
[son] pid 1778 from pid 1777
[son] pid 1779 from pid 1777
[son] pid 1780 from pid 1777
Solution 2
The one thing you have to remember is that, when you fork
, both the parent and child will continue on running the code at that point.
So, if you don't do child/parent detection correctly, the children will most likely start up their own children.
One good way for you to start up three children and no grandchildren is to use a counter in conjunction with the returned process ID from the fork
call, along the lines of the following:
#include <stdio.h>
#include <unistd.h>
#define COUNT 3
int main(void) {
# Desired and actual count.
int count = COUNT, children = 0;
// Force parent initially.
pid_t retpid = 1;
// Only fork if limit not reached AND is parent (children
// will exit loop with retpid == 0).
while (count-- > 0 && retpid > 0)
// Adjust actual count if successful.
if ((retpid = fork()) > 0)
children++;
// Detect parent, all forks returned non-zero.
if (retpid != 0) {
printf("Parent %d spawned %d/%d children\n",
getpid(), children, COUNT);
// Wait for children to finish.
while (children-- > 0)
wait(NULL);
} else {
// Otherwise you were one of the children.
printf("Child %d, sired by %d\n", getpid(), getppid());
}
return 0;
}
This outputs what you seem to be after though, due to the vagaries of scheduling, not necessarily in that order:
Parent 26210 successfully spawned 3/3 children
Child 26212, sired by 26210
Child 26213, sired by 26210
Child 26211, sired by 26210
The checking of the returned PID will ensure only the parent does any forking, and the count will limit it to a specific quantity.
One thing you also need to watch out for is output buffering. When you fork, you may end up with two processes with buffered output data.
Where the output device can be detected to be a terminal, flushing will normally occur on a newline being output, so your printf
calls probably won't duplicate output for a normal run.
You just need to be aware that you may get interesting results if you redirect your output to a file, for example.
Jite
Updated on September 29, 2020Comments
-
Jite over 3 years
Hi there I've been working on a program that forks children and later will fork more children from each child but that's not what I need help with. When I run my program (in here it is a function but works the same) I am supposed to have one parent(PPID) spawn 3 children (PIDS= 1,2,3) but what I get is either the same PID and PPID 3 times (my current code) or before I was getting 3 parents with each parent having one child and the PPIDS were different as well as the PIDS, but the PPIDs were just the same as the previous child PIDs. In my latest attempts it never displays the parent(dad) message above the child(son). It should look like this
[dad] hi am I PID 1234 and I come from ####(dont care what this number is) [son] hi i am PID 1111 and I come from PPID 1234 [son] hi i am PID 1112 and I come from PPID 1234 [son] hi i am PID 1113 and I come from PPID 1234
here is my code. I'm just looking for hints if possible unless it's just a silly mistake I've made like "oh just move the fork() to the child process" or something like that.
Also I have a child_count just so I can easily count the children.
int forking(null) { void about(char *); int i=0; int j=0; int child_count =0; about("dad"); for(i = 0; i < 3; i++ ){ pid_t child = 0; child = fork(); if (child < 0) { //unable to fork error perror ("Unable to fork"); exit(-1);} else if (child == 0){ //child process about ("son"); printf("I am child #%d \n",child_count); child_count++; exit(0);} else { //parent process (do nothing) } } for(j = 0; j < 3; j++ ){ wait(NULL);//wait for parent to acknowledge child process } return 0; }
-
Some programmer dude over 8 yearsTwo things to remember: The first is that once you have forked, the child process get a copy of the memory of the parent, and when the child modifies e.g. variables those variables are changed only in the child, the parent (or any "siblings") won't see those variable changes. The second thing is that you call to
wait
in theelse
case will block both parent and child. -
Some programmer dude over 8 yearsOh, and you have a bad case of undefined behavior in your code. You define the
child
variable, but then you use it before you initialize it. Uninitialized local variables have an indeterminate value, using them without initialization leads to UB. You might want to think about where you callfork
. -
Jite over 8 yearsoh you mean like pid_t child =0? What do you mean wait() blocks both parent and child? And about the copy of memory could you give me an example code? It makes it easier to see that point.
-
Some programmer dude over 8 yearsRegarding
wait
, you call it unconditionally after the call tofork
, so it will be called in both the parent and the child process. If you initializechild
to zero, what path will the code take in your condition? And process don't share memory, memory in a process is for that process only, and that memory includes variables likechild_count
, so modifying a variable in one process won't cause it to be modified in any other process. And again, think about where you do or should do thefork
call. -
user3386109 over 8 yearsThe
while
loop at the end needs to befor(i=0;i<3;i++)
loop. If you put aprintf
in the body of thewhile
loop you'll see that it never runs becausei
is already 3 due to the precedingfor
loop. -
Jite over 8 yearsahh thanks user3386109. I misread somewhere along the way that wait needs a while loop but it can be any loop
-