how fork() process works (operating system) - c

I am confused about fork(). For example, what will be the output of the following code?
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int value = 5;
int main() {
pid_t pid;
pid = fork();
if (pid == 0) { value += 15; return 0; }
else if (pid > 0>) { wait (NULL); printf (“Value = %d”, value); return 0}
}

The function fork() creates a new process that is a complete copy of the original process. The new process has its own memory and its own copy of all variables.
In the new child process the returned pid value is zero. The child adds 15 to its variable value and exits in the line:
if (pid == 0) { value += 15; return 0; }
The value is 5 in the original process. The original parent process has pid greater than zero and it goes to:
else if (pid > 0) { wait (NULL); printf("Value = %d", value); return 0; }
This line prints: Value = 5

The output will be "Value = 5".
The fork function will create a new process (child process) with its own address space. The child process will receive a copy of the parents process data region, heap and stack. Therefore, modifying the variable value in the child process won't affect the variable value in the parent process.

Probably you don't know or don't quite understand what fork does. Like Orest Hera and reffox both said, fork() spans a new process.
You should also know that the parent process (the once actually calling fork) will get the pid of the child process as a result from fork.
The child process starts at the point, where fork finished and returns 0 instead, thus giving the processes the chance to check, who they are:
var x = 7;
pid = fork();
if(pid < 0)
{
perror("failing to create a child process");
return SOME_ERROR;
}
if(pid == 0)
{
/* I'm the child process */
x = 9;
/* only I see that, my dad doesn't even notice that this happened */
...
} else {
/* I'm the parent process */
...
/* waiting for my child to die,
otherwise a zombie will be created,
and I DO mean a zombie */
wait(0);
/* the child is gone, now I can do whatever I want to */
}

Related

Proper Way to Fork Process

I'm trying to send a request to a server, and fork it each time beforehand:
int main(void)
{
// request send
fork();
// errx() error handling
return 0;
}
This however only causes 1 fork, then the program crashes. I've been browsing through some docs online and cannot figure out what I'm doing wrong and why it isn't forking each time it attempts to query a server.
Your main problem is execution path. Both parent and child process continue to errx, which apparently kills the active process, meaning no iterations in the parent or child. You don't check the result of fork, which is purposely there to help you tell if the function (a) worked, and (b) the current process is the parent or just-forked child.
You're better off setting up the parent process to be a watchdog, and launching the child processes to be guarded. A simple shell example is below, which sequentially launches child processes, waiting for each to terminate.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
for (int i=0; i<10; ++i)
{
pid_t pid = fork();
if (pid == 0)
{
// handle child process here
sleep(1);
return EXIT_SUCCESS;
}
if (pid < 0)
{
perror("Failed to launch child process");
exit(EXIT_FAILURE);
}
else
{
printf("child %d started\n", (int)pid);
int res = 0;
pid = wait(&res);
printf("child %d exited, result = %d\n", (int)pid, WEXITSTATUS(res));
}
}
return EXIT_SUCCESS;
}
Example Output
child 72916 started
child 72916 exited, result = 0
child 72917 started
child 72917 exited, result = 0
child 72919 started
child 72919 exited, result = 0
child 72920 started
child 72920 exited, result = 0
child 72921 started
child 72921 exited, result = 0
child 72923 started
child 72923 exited, result = 0
child 72924 started
child 72924 exited, result = 0
child 72925 started
child 72925 exited, result = 0
child 72926 started
child 72926 exited, result = 0
child 72927 started
child 72927 exited, result = 0
Monitoring Batches
For a more complicated version, the following launches child processes in batches of three, then waits for all three to terminate before launching the next batch. This is repeated three times for a total of nine processes total (ten, including the parent watchdog).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
for (int i=0; i<3; ++i)
{
// batch launch loop
int n_children = 3;
for (int j=0; j<3; ++j)
{
pid_t pid = fork();
if (pid == 0)
{
// handle child process here
sleep(1);
return EXIT_SUCCESS;
}
else if (pid < 0)
{
perror("Failed to launch child process");
--n_children;
}
else
{
printf("child %d started\n", (int)pid);
}
}
// batch wait loop
for (int j=0; j<n_children; ++j)
{
int res;
pid_t pid = wait(&res);
printf("child %d exited, result = %d\n", (int)pid, WEXITSTATUS(res));
}
}
return EXIT_SUCCESS;
}
Example Output
child 73190 started
child 73191 started
child 73192 started
child 73190 exited, result = 0
child 73191 exited, result = 0
child 73192 exited, result = 0
child 73193 started
child 73194 started
child 73195 started
child 73194 exited, result = 0
child 73193 exited, result = 0
child 73195 exited, result = 0
child 73196 started
child 73197 started
child 73198 started
child 73196 exited, result = 0
child 73197 exited, result = 0
child 73198 exited, result = 0
Hopefully you'll find some of that helpful.
You have to keep in mind that both the main (first) process and the child (second one) will execute the same code, namely the errx function call. This thing is done usually with and if/else checking for the return value of fork. That would be something like this:
if (fork() == 0) {
// you are in the child thread here
}
else {
// and here you are in the parent
}
and you split your logic between the 2 threads. If not, the threads will both go on executing the same code until the quit the execution.

Parent process not terminating

I have a parent and child process both counting upto 50 and then terminate. The parent process waits till the child process has counted upto 50 and then exits. I have written the code but it is going in infinite loop :
int main()
{
long int T_Child = 0, T_parent = 0;
pid_t procid = fork();
int T = 0;
if(procid < 0)
{
printf("\nFailed");
exit(0);
}
else if(procid == 0)
{//child
while(T_Child < 50)
{
printf("\nCHILD : %ld",T_Child);
delay(2);
T_Child++;
}
exit(1);
}
else if(procid > 0)
{//parent
while(T_parent < 50)
{
printf("\nPARENT : %ld",T_parent);
delay(2);
T_parent++;
}
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
exit(1);
}
return 0;
}
I'm a novice in this field. Please help!
Forking is not the same as threading. A fork creates a copy of the process. The
values of the variables in the child process would have the same as the
variables of the parent process at the time of the fork(). That means that
the child variables inherit the values from the parent, but changes of the
child variables are not visible by the parent.
If the parent needs to wait for the child to exit, it must call
wait or waitpid. Also if the parent needs to get a value from the child, the parent and the child
should comunicate with each other, for example using a pipe.
The following code shows how parant and child communicate with each other and
how the parent should wait for a child to exit:
#include <unistd.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
int comm[2];
// create pipe
if(pipe(comm) < 0)
{
perror("Could not create pipe");
return 1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("Could not fork");
close(comm[0]);
close(comm[1]);
return 1;
}
if(pid == 0)
{
// CHILD
// closing reading end of the pipe
close(comm[0]);
do_some_work();
int result = 50;
// write to the parant through the pipe
write(comm[1], &result, sizeof result);
// closing writing end
close(comm[1]);
exit(0);
}
// PARENT
// close writing end of pipe
close(comm[1]);
puts("Now waiting for the child to exit...");
// parent waits for child to exit
int child_status;
if(waitpid(pid, &child_status, 0) < 0)
{
perror("Could not wait");
close(comm[0]);
return 1;
}
// if child exited without any error
if(WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0)
{
// read answer from the child
int answer;
read(comm[0], &answer, sizeof answer);
printf("Child answered with %d\n", answered);
}
// closing reading end of pipe
close(comm[0]);
return 0;
}
The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content.
There is concept called Copy on Write (CoW); it's good to have knowledge about it-
Copy on Write is an optimization where the page tables are set up so that the parent and child process start off sharing all of the same memory, and only the pages that are written to by either process are copied when needed.
[Above is copied from my own answer to an old thread]
In your program you are doing:
while(T_Child < 50)
{//to ensure parent exits after child
delay(1);
}
The T_Child is initialized with 0 before fork. Because the address spaces are separate, when the child process modifies the value of T_Child, CoW creates a copy of its page — but the parent copy of T_Child still has the initial value 0. The parent process is not making any change in the value in T_Child. So, the while loop condition T_Child < 50 will always true and the loop will execute infinitely.
Instead, you should wait for child process to exit using waitpid system call. In place of while(T_Child < 50){.. loop, you should do:
waitpid(procid,&status,0);
This will make parent process wait till child process exits.

Process IDs and fork()

I have an assignment that is asking me to identify the values of the process IDs at lines A, B, C, and D, assuming that the actual pids of the parent and child are 2600 and 2603, respectfully.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid, pid1;
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if(pid == 0){ /* child process */
pid1 = getpid();
printf("child: pid = %d", pid); /* A */
printf("child: pid1 = %d", pid1); /* B */
}
else { /* parent process */
pid1 = getpid();
printf("parent: pid = %d", pid); /* C */
printf("parent: pid1 = %d", pid1); /* D */
wait(NULL);
}
}
I've already been given the solutions for the problem, but I'm having trouble understanding the fork() function. Why would it return EITHER -1, 0, or some positive number? Why does it not consistently return a certain value? For example, when we assign pid = fork(), it can be a value of -1, 0, or some positive number. Even if I know that, I don't know how the values become what they are. I know that, initially, the child process is given a copy of the parent data. Ordinarily, my tactic is to step through the code line-by-line and adjust the variables as they are modified to determine output, but this example seems nondeterministic. I feel like I'm viewing this problem completely wrong, but I don't know how to change my thought process. I've reviewed the documentation for fork() here but it didn't clarify anything for me.
Additionally, why don't we use a get function, i.e. pid.getID() in the if/else-if statements? Doesn't this mean that pid_t and int are equivalent?
A step-by-step explanation of this code would be greatly appreciated.
For reference, the solutions are 0, 2603, 2603, and 2600.
fork() creates a new process that's an almost exact duplicate of the original process. Both processes continue running, starting from the return of the fork() function. In the parent process, fork() returns the PID of the child (a positive number), while in the child process fork() returns 0 (that's how it knows that it's the child).
If, for some reason, the system wasn't able to create a new process, fork() returns -1 in the parent instead of the child's PID, and errno is set to the error code with the reason for the failure.
You could do an equivalent test using getpid(), it would just be more work:
pid_t parentPID = getpid();
fork();
pid_t myPID = getpid();
if (myPID == parentPID) {
// this is the parent
} else {
// this is the child
}
Having fork() return 0 in the child simplifies it, since you get all the information you need from that one call, instead of having to call getpid() twice.

Theory,Processes fork()

Goodmorning, i would like to ask 2 things..
1) what returns a fork() did on a child which has already a pid==0 ? if i continue to fork on every son, each of them will have 0 as pid ?? or not ?
2) this is my file Buffer.c and it runs on a single process.
At the beginning it forks() out some Producers who produce() and some Consumers who consume() ,but I am afraid that every producers enters in the next for cicle and it starts to produce himself other consumers!! because it write pid=-1 so...
I want that this piece of code produce only P producers and C consumers, but i need to know why every producer do not create other consumers!
Can you help me,maybe giving me a scheme of how many processes i will create with this code?
Maybe doing a scheme as this:
Father:
8 producers
-
-
-
...
each of them produces: 5 consumers
etc etc......
int main(int argc, char **argv) {
/....
pid_t pid;
pid_t cons_pid[C];
/* fork producers */
pid = -1;
for(i=0; i<P && pid!=0; i++)
pid=fork();
switch(pid) {
case -1:
...
case 0:
/* GENERIC PRODUCER i */
...
/* PRODUCE() */
printf("Producer %d exits\n",i);
...
return 0;
}
/* fork consumers */
pid = -1;
for (j=0; j<C && pid!=0; j++)
pid = cons_pid[j] = fork();
switch(pid) {
case -1:
....error
case 0:
/* GENERIC CONSUMER j */
CONSUME()....
}
return 0;
}
what returns a fork() did on a child which has already a pid==0
0 is not a valid PID, hence by definition there can't be an process with PID=0 and thus PID=0 is a perfectly well defined return for indicating child status.
if i continue to fork on every son, each of them will have 0 as pid
No process ever has PID=0. All PIDs are greater than zero! A zero is just the return value received by the newly forked process to indicate that it's the child. The actual PID a child process got is queried using the getpid function from the child process. However the parent process can't perform such a query, since in the time between fork and a assumed query function call, the child may already have terminated (race condition). So you want fork to return the PID to the parent directly.
BTW: The terminology is parent and child not father and son (processes are things not people, despite what the TRON movies depict).
Regarding your code snippet: A switch statement is the wrong choice here. You want to use an if statement.
fork() splits up the current process into a father and a child. The child will have a new PID, the father retains the old PID. In both processes fork() returns after the splitting. In the father the return value will be the PID of the child (to make it known), and in the child the return value will be 0.
1) The lowest possible process ID is 1, this is the ID of the init process from which all other processes are forked. Therefore, it is not possible for a child or for your parent process to "already have ID 0". Your child's process ID is necessarily greater than 1. Thus, the problem that you are afraid of cannot happen.
2) The confusion that you state is the reason why fork (which returns twice, once for the parent and once for the newly created child!) has a somewhat "weird" return value which can have so many different values:
it can be -1, then something went wrong, and no child was created.
it can be a positive value, then you are in the parent process, and the value is the child's process ID. It's as if you called any other "normal" function that just returned normally.
it can be 0, then your code knows it is now running in the child process.
You must examine the return value (if()) so you know what process you are in. Then no such thing as you decribe can happen (or, should happen, this presumes your code does not have any bugs).
EDIT:
The code can be rewritten slightly so it gets rid of the && pid!=0 inside the loop and thus looks a bit less scary overall:
int main()
{
int pid, i;
pid_t cons_pid[C];
for(int i=0; i<P; ++i)
{
pid=fork();
if(pid == -1) exit(1); /* fork error */
if(pid == 0) { producer(); return 0; }
}
for(i=0; i<C; ++i)
{
pid = fork();
if(pid == -1) /* fork error */
{ /* should do a kill_producers(); here */ exit(2); }
else if(pid == 0) /* consumer */
{ consumer(); return 0; }
else /* master process, remember all consumer pids */
{ cons_pid[j] = pid; }
}
/* ... */
return 0;
}

Child Process Creation through fork() in C

I'm completely new to C and learning about processes. I'm a little confused as to what the code below is actually doing, it's taken from Wikipedia but I've seen it in several books and am unsure as to why, for example, we do pid_t pid; then pid = fork();. My reading seem to suggest the child process returns a pid of 0, however, I thought the very original parent process will maintain the pid of 0 after seeing a tree with the root as pid 0.
What does, for example, pid = fork(); do to the parent? As doesn't it do the same thing for the child? And doesn't pid = fork(); put it into a loop as it will do this for each child?
Basically, could someone explain each step to me as if I were, say, five? Maybe younger? Thanks!
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
int main(void)
{
pid_t pid;
/* Output from both the child and the parent process
* will be written to the standard output,
* as they both run at the same time.
*/
pid = fork();
if (pid == -1)
{
/* Error:
* When fork() returns -1, an error happened
* (for example, number of processes reached the limit).
*/
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
/* Child process:
* When fork() returns 0, we are in
* the child process.
*/
int j;
for (j = 0; j < 10; j++)
{
printf("child: %d\n", j);
sleep(1);
}
_exit(0); /* Note that we do not use exit() */
}
else
{
/* When fork() returns a positive number, we are in the parent process
* (the fork return value is the PID of the newly created child process)
* Again we count up to ten.
*/
int i;
for (i = 0; i < 10; i++)
{
printf("parent: %d\n", i);
sleep(1);
}
exit(0);
}
return 0;
}
After executing the fork() function, you have two processes, which both continue executing after the fork call. The only difference between the two processes is the return value of fork(). In the original process, the "parent", the return value is the process id (pid) of the child. In the new cloned process, the "child", the return value is 0.
If you wouldn't test the return value of fork(), both processes would be doing exactly the same.
NB: to understand why the fork() function is useful, you need to read what the exec() function is doing. This function loads a new process from disk, and replaces the caller process with the new process. The combination of fork() and exec() is actually the way to start a different process.
Upon successful completion, fork() (source):
shall return 0 to the child process
and shall return the process ID of the child process to the parent process.
The example you gave is well explained. However, I would like to precise that Both processes (parent and child) shall continue to execute from the fork() function.
if you would like to know the PID of the child (from the code of the child), use getpid API.
fork is a function that returns twice - once for the parent, once for the child.
For the child, it returns 0, for the parent the pid of the child, any positive number; for both processes, the execution continues after the fork.
The child process will run through the else if (pid == 0) block, while the parent will run the else block.

Resources