(UNIX) How Does fork() Work in a Loop? - linux

I have this program
childpid = 0;
int i, n;
for(i=1; i < n; i++)
if((childpid = fork())
break;
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n,
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
It says that since a parent's process's childpid variable does not have a value of 0, it will break out of a loop. A a child process's pid is 0, and will become a parent in the next iteration.
To my knowledge, a new process is created with the code after the line fork() has been called. If a parent process breaks out of the loop as its childpid is not 0, does that not mean that the printf statement will be run once and the program will terminate since the loop has ended?
I am confused about how this program runs.
I also have this code
for(i=1; i < n; i++)
if( ((childpid = fork()) <= 0)
break;
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n,
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
This creates a fan of processes and does the opposite of the first program. The child process breaks out of the loop since its chilpid is equal to 0, and the parent processes run in the loop.
I have an exam on Monday, and I've understood everything else
please do help :/

does that not mean that the printf statement will be run once and the program will terminate since the loop has ended?
Yes it will. But not before it has spawned a child process to carry on its legacy.
Here's a poorly drawn diagram of what's going on. In code snippet #1, the process forks itself, the parent dies, and then the child keeps going in its place.
In code snippet #2, the process forks itself, the child dies, then the parent keeps going.
In each case, the result is a long sequence of print statements.

I edited your first code a bit, and added "{ }" at the beginning and end of the if statement and for loop:
**int main()
{
int childpid = 0;
int i, n;
n=5;
for(i=1; i < n; i++){
if((childpid == fork()))
{
break;
}
fprintf(stderr, "i:%d process ID: %ld parent ID: %ld child ID: %ld\n",
i, (long)getpid(), (long)getppid(), (long)childpid);
}
wait(0);
return 0;
}**
And this was the result:
i:1 process ID: 3443 parent ID: 2790 child ID: 0
i:2 process ID: 3443 parent ID: 2790 child ID: 0
i:3 process ID: 3443 parent ID: 2790 child ID: 0
i:4 process ID: 3443 parent ID: 2790 child ID: 0
What happens is that the main process( the parent) does all the prints in the for loop, while each child process exits right after the if statement.
While on your second code, instead of
if( ((childpid = fork()) <= 0)
break;
you could write:
int f=fork();
if (f<0)
{
perror("can't create child\n");
}
if(f==0)
{
break;
}
Because if "f" is less than 0, it means that the child was not created successfully, if it was, it breaks out imediatley.

Related

Two child processes create 3 child process each

I'm struggling with making a C program, where the parent process creates 2 child processes, and those 2 childs create 3 child process on their own. I get the 6 child-child processes as outcome, but 2 of the 6 is the child of the parent. I can't seem to make this work.
Any help would be highly appreciated!
pid_t pid[2];
pid_t pid2[3];
for (i=0;i<2;i++) {
pid[i] = fork();
if (pid[i] == 0) {
break;
}
}
if (pid[0] != 0 && pid[1] != 0) {
// That's the father, it waits for all the childs
printf("The parent process [pid: %d, ppid: %d]\n",getpid(),getppid());
for(i=0;i<2;i++) {
wait(&tmp);
}
} else {
printf("I'm a child process [pid: %d, ppid: %d]\n",getpid(),getppid());
for (k=0; k<3; k++){
pid2[k]=fork();
if (pid2[k]==0){
break;
}
}
if (pid2[0] == 0 && pid2[1] == 0 && pid2[2] == 0){
}
else{
printf("Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
}
When the pid2[k] is 0 for any k, it is a grandchild.
So it only is a the first level child, when all pid2's are positive:
/* correct code */
if (pid2[0] > 0 && pid2[1] > 0 && pid2[2] > 0){
printf("I am a child with 3 children\n");
}
else{
printf("Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
What you wrote will happen only once for each first level child: The first grandchild k=0 will have pid2[0]==0, and will not update pid2[1] and pid2[2], these can be random or 0, depending on your compiler.
The other grand children will have the pid of their oldest brother in pid2[0].
/* incorrect code with additional printf */
if (pid2[0] == 0 && pid2[1] == 0 && pid2[2] == 0){
printf("I am one of the oldest children\n");
}
else {
printf("Child or Younger Child of child [pid: %d, ppid: %d]\n",getpid(),getppid());
}
Now you should aldo handle situations where the fork() fails (pid< 0).

About Inter-process communication in C, Using pipe()

I'm trying to write sort function.
This function may fork many children to help itself to sort the given input.
When my function has only one child it is easy to use pipe(). I just create
int fd[2];
then everything is fine but I don't know what to do when there are many children. Should I create fd[Children*2] pipes or fd[2] is enough?
And how can i use these pipes to communicate with the child that I want (since there are many children)?
My main process will fork children, this is just one part of the code, I'm forking children and getting their pids into pid array
pid_t main = getpid();
int N = 30;
pid_t* children = (pid_t*) malloc(sizeof(pid_t) * N);
for(i = 0; i < N; i++){
pid_t child = fork();
if ( child == 0){
pid_t me = getpid();
printf("I'm a child and my pid is: %d\n", me);
sleep(1);
// exit(4);
return me * 2;
} else if ( child < 0){
// printf("Could not create child\n");
} else {
children[i] = child;
// printf("I have created a child and its pid %d\n", child);
}
}
If only the main process needs to create and communicate with children, and the children don't need to communicate with each other, create a separate pipe for each child in the main process before forking the child. The call to pipe() could be placed in your loop, before calling fork(). You could use a 2-dimensional array like fd[NUM_CHILDREN][2] to keep track of the file descriptors. If the data will be arriving asynchronously, poll() or select() can be used to find out when something is available to be read.

How to fork multiple processes from a same parent?

I am trying to create multiple processes from a same parent, but it always ended up with more processes than expected. I couldn't figure out how to do it and need some help here.
I found a piece of code online and tried it,
int main ()
{
pid_t pid=0;
int i=0;
for (i=0; i<3; i++)
{
pid=fork();
switch(pid)
{
case 0:
{
cout<<"\nI am a child and my pid is:"<<getpid();
cout<<endl;
exit(0);
break;
}
default:
{
cout<<"\nI am a parent and my pid is: "<<getpid();
cout<<"\nMy child pid is: "<<pid;
cout<<endl;
wait(NULL);
break;
}
}
}
return 0;
}
This code does work and creates 3 children from same parent. However, it seems like that's because after each child process was created, it was terminated immediately. So it won't fork more grandchild process in the next round of for loop. But I need to keep these child processes running for sometime and they need to communicate with the parents.
A child process may immediately break the loop to continue its work outside
int main ()
{
cout<<"\nI am a parent and my pid is: "<<getpid()<<endl;
pid_t pid;
int i;
for (i=0; i<3; i++)
{
pid=fork();
if(pid == -1)
{
cout<<"Error in fork()"<<endl;
return 1;
}
if(pid == 0)
break;
cout<<"My child "<<i<<" pid is: "<<pid<<endl;
}
if(pid == 0)
{
cout<<"I am a child "<<i<<" and my pid is "<<getpid()<<endl;
wait(NULL); // EDIT: this line is wrong!
}
else
{
cout<<"I am a parent :)"<<endl;
wait(NULL); // EDIT: this line is wrong!
}
return 0;
}
EDIT
The wait(NULL) lines are wrong. If the process has no children active, wait() has no effect, so it's useless in children here. OTOH in the parent process wait() suspends the execution until any of children exits. We have three children here, so would have to wait() three times. Additionally one can't know in advance the order of children completion, so we would need much more sophisticated code for that. Something like this:
struct WORK_DESCRIPTION {
int childpid;
// any other data - what a child has to do
} work[3];
for(i=1; i<3; i++) {
pid=fork();
...
work[i].childpid = pid;
}
if(pid == 0) // in a child
{
do_something( work[i] );
}
else
{
int childpid;
while(childpid = wait(NULL), childpid != 0)
{
// a child terminated - find out which one it was
for(i=0; i<3; i++)
if(work[i].childpid == childpid)
{
// use the i-th child results here
}
}
// wait returned 0 - no more children to wait for
}

How to run child processes concurrently

I want child processes run concurrently. Is it OK to write as to achieve this:
for(p = 0; p < N; p++){ //there will be N child processes
pidOfChild = fork();
if(pidOfChild == -1){
printf("fork() failed.\n");
exit(1);
}
else if(pidOfChild == 0){
//do sth
printf("I am a child and my PID is %d.\n", getpid());
exit(0);
}
}
It is okay, and if your parent process exits, you don't need to wait.

second call prctl() dont work

I try write program, which realize next idea:
After start, program using fork() and:
parent process stopped on function wait() (for waiting death child process);
child process use prctl(PR_SET_PDEATHSIG, SIGHUP), and setup signal handler (It's helps detect parent death);
After death any process, program use fork() again.
void forking_process() {
pid_t id;
printf("forking_process is called!\n");
if (id = fork()) {
parent_process_operation();
} else {
child_process_operation();
}
}
void parent_process_operation() {
int status = 0;
printf("It's parent process! Pid = %d\n", (int)getpid());
pid_t chid = wait(&status);
printf("Terminated child process with PID = %d\n", chid);
inform_about_parent_death(status);
}
void child_process_operation() {
printf("It's child process! pid = %d, ppid = %d\n",
(int)getpid(), (int)getppid());
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = inform_about_parent_death;
if (sigaction(SIGHUP, &sa, NULL))
fprintf(stderr, "sigaction error\n");
prctl(PR_SET_PDEATHSIG, SIGHUP);
while(1) {
printf("."); fflush(stdout);
sleep(1);
}
}
void inform_about_parent_death(int i) {
printf("Process is dead. Restart!\n");
forking_process();
}
int main (void) {
forking_process();
return EXIT_SUCCESS;
}
If I run this application, and in another terminal kill child process - then will create child process.
If I kill the parent process once, - signal handler started and call fork().
If I again kill the parent process, - signal handler not responded.
That is - prctl() in first process work, but prctl() in second child process don't work.
Why it is happen? How I can correct it's program?

Resources