Could someone explain how fork works? - c

I don't really understand how fork() works.I understand examples with one fork,but when there are more than one call I don't.I have an example like this and it prints 4 lines of hello, how many processes are created?
int main(void)
{
fork();
fork();
printf("hello\n");
return 0;
}

After fork() call, both processes (original and spawned) continue to execute from next line of code. So both processes execute second fork() instruction, so in the end you have 4 processes. Hence you see 4 instances of "hello" lines printed.
One picture is worth a thousand words:

The fork() syscall essentially creates a "clone" of the process executing it. Both "clones" run almost identically (except for the return value of fork()).
The first call to fork() is executed by one process (let's call that one "P"), which creates a second process "C". Now there are two processes, which both execute the second line in your main() function. So both processes, P and C, create a new process. This is why you end up with a total of 4 processes, all of which print "hello" exactly once.
The following example might make that behaviour a bit clearer:
int main() {
printf("process %d: start\n", getpid());
int r1 = fork();
printf("process %d: first fork() returned %d\n", getpid(), r1);
int r2 = fork();
printf("process %d: second fork() returned %d\n", getpid(), r2);
}
On my system, it outputs the following:
process 12953: start
process 12953: first fork() returned 12954
process 12954: first fork() returned 0
process 12953: second fork() returned 12955
process 12955: second fork() returned 0
process 12954: second fork() returned 12956
process 12956: second fork() returned 0

Related

Using switch statements to fork two processes

I'm taking an intro to C course and I've become a bit stumped on the first assignment. We've been tasked with creating a parent processes and two child processes. All of the examples the text has shown us so far involve switch statements with one parent and one child. I'm a bit confused about how to translate this into one parent and two child processes. Here is what I have so far:
#include <stdio.h>
int main() {
int i, pid, status;
pid = fork();
switch(pid) {
case -1:
/* An error has occurred */
printf("Fork Error");
break;
case 0:
/* This code is executed by the first parent */
printf("First child process is born, my pid is %d\n", getpid());
printf("First child parent process is %d\n", getppid());
for (i=1; i<=10; i++)
printf("First child process, iteration: %d\n", i);
printf("First child dies quietly.\n");
break;
default:
/* This code is executed by the parent process */
printf("Parent process is born, my pid is %d\n", getpid());
wait(&status);
printf("Parent process dies quietly.\n");
}
}
This works perfect for this one process:
Parent process is born, my pid is 10850
First child process is born, my pid is 10851
First child parent process is 10850
First child process, iteration: 1
First child process, iteration: 2
First child process, iteration: 3
First child process, iteration: 4
First child process, iteration: 5
First child process, iteration: 6
First child process, iteration: 7
First child process, iteration: 8
First child process, iteration: 9
First child process, iteration: 10
First child dies quietly.
Parent process dies quietly.
Essentially I just need to do the same thing with a second process... something like:
printf("Second child process is born, my pid is %d\n", getpid());
printf("Second child parent process is %d\n", getppid());
for (k=1; k<=10; k++)
printf("Second child process, iteration: %d\n", i);
printf("Second child dies quietly.\n");
break;
But I'm just not sure how to get there from what I have so far. Am I approaching this correct way? Is there a better method I should be using? Thanks so much.
There is a general rule. When you use fork(2) you should always handle the three cases below:
fork gave 0, you are in the child process
fork gave a positive pid_t, you are in the parent process
fork failed and gave -1
People (newbies) sometimes tend to forget the last (failure) case. But it does happen, and you might easily test that case by using setrlimit(2) with RLIMIT_NPROC in your grand-parent process to lower the limit on processes, often that grand-parent process is your shell (e.g. using ulimit Bash builtin with -u).
Now, how to handle the three cases is a matter of coding style. You can use switch but you can use two if. Your code uses a switch and is right to do so.
As a general rule, most system calls (listed in syscalls(2)) can fail, and you almost always need to handle the failure case (see errno(3) and use perror(3)).
Read also Advanced Linux Programming (freely downloadable).
I'm a bit confused about how to translate this into one parent and two child processes.
The fork system call is creating (on success) exactly one child process. So if you need two children, you should call it twice (and test failure on both calls) in a row. If you need one child and one grand child, you should do the second fork only when the first one gave 0. Of course you need to keep both (successful and positive) pid_t -e.g. in two variables- returned by your two calls to fork.
To avoid zombie processes, every successful fork should later have its wait system call (e.g. waitpid(2) or wait or wait4(2) or wait3). Where you do that wait depends if you want to have both children running at the same time or not. But every successful fork should have a corresponding successful wait call.
Read also signal(7) (and signal-safety(7)) about SIGCHLD if you want to be asynchronously notified about child processes change - notably termination. A common way is to install a SIGCHLD signal handler (e.g. using sigaction(2) or the old signal(2)) which just sets some global volatile sigatomic_t flag and test then clear that flag in convenient place in your code (e.g. in some event loop using poll(2)).
NB: notice that fork is not about C programming (fork is not defined in the C11 standard n1570 or its predecessor C99). It is a POSIX and Linux thing. Windows or z/OS or an Arduino microcontroller don't have it natively, but are programmable in some standard C.
You can put fork and switch case in loop so that it forks multiple processes, something like below:
Edit: You can remove if condition to call wait after each fork, alternately if you want to launch all children then wait for them to terminate, in each iteration you can collect pid of each child (in parent process ie in default switch case) in an array and in last iteration call waitpid in a loop(for each pid) to ensure each child process has exited
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int i, pid, status;
int j = 0;
int numChildren = 2;/*Change it to fork any number of children*/
for(j = 0;j< numChildren;j++)
{
pid = fork();
switch(pid) {
case -1:
/* An error has occurred */
printf("Fork Error");
break;
case 0:
/* This code is executed by the first parent */
printf("First child process is born, my pid is %d\n", getpid());
printf("First child parent process is %d\n", getppid());
for (i=1; i<=10; i++)
printf("First child process, iteration: %d\n", i);
printf("First child dies quietly.\n");
exit(0);/*Otherwise it will fork its own child*/
break;
default:
/* This code is executed by the parent process */
printf("Parent process is born, my pid is %d\n", getpid());
if(j == (numChildren - 1))/*You can remove this condition to wait after each fork*/
{
wait(&status);
printf("Parent process dies quietly.\n");
}
}
}
}
To make 2 child you call fork()2x. So call fork with 2 different variable and then wait for them both.

Understanding the fork() command Posix API

#include<iostream>
#include<unistd.h>
#include<stdio.h>
using namespace std;
int main()
{
fork();
fork();
fork();
fork();
printf("*"); /*This prints 16 stars*/
return 0;
}
When working with fork(), why does it print 16 *'s?
I understand that fork() generates a new
child process that both execute the same process which would explain why one fork generates 2 stars but, with four forks it prints 16 which I can see that it doubles with each fork().
But I am not understanding why. Is each fork executing the functions and parameters below it?
Because the first fork will split into two process, the second fork() call will be called by those two processes, splitting those two processes into 4. This will continue until all the fork() calls have been called in each process. So you end up having 2^4 = 16 calls to printf("*")
In the "diagram" each bar represents the number of processes that are executing when the function is called. So the function is executed as many times as there are bars.
| fork() // The first processes creates a second (2 total)
| fork() | // Those 2 processes start 2 more (4 total)
|| fork() || // Those 4 processes start 4 more (8 total)
|||| fork() |||| // Those 8 processes start 8 more (16 total)
|||||||| printf() |||||||| // resulting in 16 calls to printf()
Is each fork executing the functions and parameters below it?
Yes, as you can see from the diagram, when a process forks the created process (and the one that created it) continues execution on the next instruction after the fork.
When you call fork(), it create a new process. You duplicate your application, and then the 2 applications continues to run and execute new instructions after the fork() call
printf("i'm the main thread\n");
fork();
printf("i'm executed 2 times\n");
fork(); //this fork is so executed 2 times, so 2 new processes, so 4 processes for all
printf("i'm excecuted 4 times\n");
fork(); //this fork is executed 4 times to ! So you have now 8 processes;
// and etc ..
fork(); //this fork is executed 8 times, 16 process now !
printf("*"); // executed 16 times
The new processes share all memory before the fork(), old changed states are for the current thread.
if you want to do anothers things depending the process :
pid_t p;
int i = 1;
p = fork();
if(p == 0)
{
printf("I'm the child\n");
i = 2;
exit(0); //end the child process
}
printf("i'm the main process\n");
printf("%d\n", i); //print 1

When to call fork()?

I have two code samples here
#include<stdio.h>
int main()
{
int i = 0;
i++;
fork();
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
return 0;
}
user#Ubuntu ~/Arena/c $ ./a
i - 1, pid - 6765, addr -0x7fffd892950c
i - 1, pid - 6766, addr -0x7fffd892950c
with my second program being
#include<stdio.h>
int main()
{
int i = 0;
i++;
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
fork();
return 0;
}
user#Ubuntu ~/Arena/c $ ./b
i - 1, pid - 6772, addr -0x7fff39120f2c
Well as far as I know fork should create a COMPLETE copy of the parent program from top to bottom and execute it, if it is that way why is the position of fork() call making such a big difference ? Could some one explain why is the printf omitted in my second program ?
fork() creates a copy of the process, and continues executing both processes at the point you call fork().
So in your second example, your printf is executed before the fork when there is only one process.
Fork creates a complete copy of your program but execution continues from the point in which fork is called. Put printf after the fork and see what happens.
Usually a fork call will be followed by a check if fork returned the pid of the child or not. If it did, then your current running process is the parent which received the child's pid in order to be able to manage the child, if it didn't then your current running process is the child.
For further enlightenment, try:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int i = 0;
i++;
printf("A: i - %d, pid - %d, addr -%p", i, getpid(), &i);
fork();
printf("\nB: i - %d, pid - %d, addr -%p\n", i, getpid(), &i);
return 0;
}
The first printf() doesn't include a newline, so the output is held in memory. The second printf() includes newlines, so the output appears after the program has forked. You should see the same information in the two lines tagged A; you should see different information in the two lines tagged B.
In a single-threaded application, the parent and child processes are almost identical except for the PID, Parent PID, and the value returned by fork(). For the full details, see the POSIX specification of fork().

Forking and Process Management

System information: I am running 64bit Ubuntu 10.10 on a 2 month old laptop.
Hi everyone, I've got a question about the fork() function in C. From the resources I'm using (Stevens/Rago, YoLinux, and Opengroup) it is my understanding that when you fork a process, both the parent and child continue execution from the next command. Since fork() returns 0 to the child, and the process id of the child to the parent, you can diverge their behavior with two if statements, one if(pid = 0) for the child and if(pid > 0), assuming you forked with pid = fork().
Now, I am having the weirdest thing occur. At the beginning of my main function, I am printing to stdout a couple of command line arguments that have been assigned to variables. This is this first non assignment statement in the entire program, yet, it would seem that sometimes when I call fork later in the program, this print statement is executed.
The goal of my program is to create a "process tree" with each process having two children, down to a depth of 3, thus creating 14 total children of the initial executable. Each process prints its parent's process ID and its process ID before and after the fork.
My code is as follows and is properly commented, command line arguments should be "ofile 3 2 -p" (i haven't gotten to implementing -p/-c flags yet":
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
if(argc != 5)//checks for correct amount of arguments
{
return 0;
}
FILE * ofile;//file to write to
pid_t pid = 1;//holds child process id
int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have
printf("%d%d", depth, arity);
ofile = fopen(argv[1], "w+");//opens specified file for writing
int a = 0;//counter for arity
int d = 0;//counter for depth
while(a < arity && d < depth)//makes sure depth and arity are within limits, if the children reach too high(low?) of a depth, loop fails to execute
//and if the process has forked arity times, then the loop fails to execute
{
fprintf(ofile, "before fork: parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent and self id to buffer
pid = fork(); //forks program
if(pid == 0)//executes for child
{
fprintf(ofile, "after fork (child):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
a=-1;//resets arity to 0 (after current iteration of loop is finished), so new process makes correct number of children
d++;//increases depth counter for child and all of its children
}
if(pid > 0)//executes for parent process
{
waitpid(pid, NULL, 0);//waits on child to execute to print status
fprintf(ofile, "after fork (parent):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
}
a++;//increments arity counter
}
fclose(ofile);
}
When I run "gcc main.c -o ptree" then "ptree ofile 3 2 -p", the console is spammed with "32" a few times, and the file "ofile" is of seemingly proper format, but a bit too large for what I think my program should be doing, showing 34 child processes, when there should be 2^3+2^2+2^1=14. I think this is somehow related to the statement that is printing "32", as that would seem to possibly spawn more forks than intended.
Any help would be greatly appreciated.
When you call printf, the data is stored in a buffer internally. When you fork, that buffer is inherited by the child. At some point, (when you call printf again, or when you close the file), the buffer is flushed and data is written to the underlying file descriptor. To prevent the data in the buffer from being inherited by the child, you can flush the FILE * before you call fork, via fflush.

Help with output generated by this C code using fork()

I am trying to figure out the output for a block of C code using fork() and I am having some problems understanding why it comes out the way it does. I understand that when using fork() it starts another instance of the program in parallel and that the child instance will return 0. Could someone explain step by step the output to the block of code below? Thank you. EDIT: I FORGOT TO ADD THE EXIT(1) AFTER THE FOR LOOP. MY APOLOGIES.
main() { int status, i;
for (i=0; i<2; ++i){
printf("At the top of pass %d\n", i);
if (fork() == 0){
printf("this is a child, i=%d\n", i);
} else {
wait(&status);
printf("This is a parent, i=%d\n", i);
}
}
exit(1);
}
What happens on the first loop is that the first process forks. In one, fork() returns 0 and in the other it returns the pid of the child process So you'll get one that prints out "this is a child" and one that prints out "this is a parent". Both of those processes continue through the loop, incremement i to 1 and fork() again. Now you've got four processes: two children and two parents. All four processes will increment i to 2 and break out of the loop.
If you increased the loop termination condition to i<3 then the next time around the loop all four processes will execute fork() and you'd have eight processes in total. If there was no limit in the loop, you'd have a fork bomb where you'd just exponentially create more and more processes each loop until the system runs out of resources.
This code can be tricky to explain. The reason why is that the first child does not exit and will itself call fork. Try modifying the code to include the process id on each print line such as:
printf("At the top of pass %d in pid %u\n", i, getpid());
Then notice how the child becomes the parent...

Resources