why does fork program printf execute more time [duplicate] - c

This question already has answers here:
Output of fork() calls
(3 answers)
Closed 8 years ago.
from the man page of fork i read fork create duplicate of parent process. But not able to understand why below program printf execute 8 times. I read Working of fork() in linux link also.
#include <stdio.h>
int main()
{
fork();
fork();
fork();
printf("process\n");
}

In general for n forks in this manner will execute the next statements (in this case printf) 2^n times.
Here is how:
|
+-fork()----------------------------------+
| |
+-fork()-------------+ +-fork()-------------+
| | | |
+-fork()---+ +-fork()---+ +-fork()---+ +-fork()---+
| | | | | | | |
print() print() print() print() print() print() print() print()

Fork works like a binary tree. So its always 2^x number of processes on every x number of fork calls.
Lets understand with your example.
First fork() call:
When the first fork() is called. The parent process creates a new process. So we have 2
threads.
Second fork() call:
At this point we have two processes(main process and a new created process).These two threads will call second fork individually and create 2 new processes each. so we have 4 threads.
You might have got the idea by now. Every time a fork() is encountered all the processes create their respective child processes(double themselves).

Related

Number of print statements Fork() [duplicate]

So I have to find the output of this code which is using the fork() method. I thought the output was 5 "hello" s but instead I got 8. Why is that? This is the code:
#include "csapp.h"
void doit()
{
Fork();
Fork();
printf("hello\n");
return;
}
int main()
{
doit();
printf("hello\n");
exit(0);
}
Here's what your code is doing:
main->doit()->Fork()->Fork()->printf()->return->printf()->exit()
| |
| ----->printf()->return->printf()->exit()
|
----->Fork()->printf()->return->printf()->exit()
|
----->printf()->return->printf()->exit()
As you can see, you have a total of 8 calls to printf().
It would have been easier for you to see what was going on if you chose to print different strings in your main and doit functions.
Setting breakpoint on each printf() call is another effective strategy for figuring out these kinds of problems.
First you call fork and your one process forks into two. Then you call fork in each resulting process and you have a total of 4. Then the 4 processes print hello, return, and print hello again, for a total of 8 hellos.
You create process #1. Before printing anything, process #1 calls fork() and generates a clone that we will call process #2. Both processes #1 and #2 call fork() again, cloning into processes #3 and #4. Now you have 4 processes and each one of them will print hello twice. How many hello are printed?

why does this fork() out put produce 8 instead of 5?

So I have to find the output of this code which is using the fork() method. I thought the output was 5 "hello" s but instead I got 8. Why is that? This is the code:
#include "csapp.h"
void doit()
{
Fork();
Fork();
printf("hello\n");
return;
}
int main()
{
doit();
printf("hello\n");
exit(0);
}
Here's what your code is doing:
main->doit()->Fork()->Fork()->printf()->return->printf()->exit()
| |
| ----->printf()->return->printf()->exit()
|
----->Fork()->printf()->return->printf()->exit()
|
----->printf()->return->printf()->exit()
As you can see, you have a total of 8 calls to printf().
It would have been easier for you to see what was going on if you chose to print different strings in your main and doit functions.
Setting breakpoint on each printf() call is another effective strategy for figuring out these kinds of problems.
First you call fork and your one process forks into two. Then you call fork in each resulting process and you have a total of 4. Then the 4 processes print hello, return, and print hello again, for a total of 8 hellos.
You create process #1. Before printing anything, process #1 calls fork() and generates a clone that we will call process #2. Both processes #1 and #2 call fork() again, cloning into processes #3 and #4. Now you have 4 processes and each one of them will print hello twice. How many hello are printed?

How many times are executed the programs invoked by execl?

Can you help me with this?
How many times are executed the programs "exam" and "students" invoked by execl? I think the correct answer is 8 runtimes for program "exam" and 0 for "students", because in the two first forks will be created 3 child processes, after that in loop the first fork() will create more 4 processes, since the three children already created also will run this code, thereafter we have a exec that will replace the current code of the 7 processes created and of the actual program and run it(program "exam") 8 times. My reasoning is correct?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(){
int i;
pid_t
pid=fork();
pid=fork();
for(i=0;i<5;i++){
pid=fork();
execlp("exam","exam",NULL);
if(pid==0){
break;
}
}
execlp("students", "students","sistcomp",NULL);
return 0;
}
Theoretically, you are right. Let me draw a diagram to explain:
+---1 ...
|
+---+---2 ...
|
----+---+---3 ...
fork()|
+---4+---- execlp("exam","exam",NULL);
fork() |
+---- execlp("exam","exam",NULL);
^
after the first two fork()
you see, after 2 fork(), we get 4 process. Take the No.4 as an example, it enter for loop and fork() again, then we get another child process here, this child process and its father will exec execlp("exam","exam",NULL); as you see this will replace the current code.The same is true for No.1, No.2 and No.3.
So, it will be 8 runtimes for program "exam" and 0 for "students".
But, when you run this code, runtimes for program "exam" may be 7 or 6, it may be caused by Copy-on-write(I am not pretty sure about this)
PS:
It is a good practice to use execlp like this:
if (pid == 0)
execlp("exam","exam",NULL);
or
if (pid != 0)
execlp("exam","exam",NULL);

How can I keep execv from killing my program? [duplicate]

This question already has answers here:
Does the C execv() function terminate the child proccess?
(4 answers)
Differences between fork and exec
(9 answers)
Closed 9 years ago.
My assignment is to write a simple linux shell. I'm on external commands. We need to use execv.
for (int i = 0; i < count; i++){
char path[1024];
strcpy(path, PATHS[i]); // PATHS is an array of cstrings, the paths in $PATH
strcat(path, "/");
strcat(path, command[0]); // command and commands are essentially the same
printf("%d %s",i,path); // they are essentially argv[]
if (!execv(path, commands)) // for ls -l $HOME
break; // commands[0] = ls [1] = -l [2] = my home dir
right now I'm only testing it with ls. ls runs exactly as it should, but the program closes immediately after execv succeeds. Is there any way for me to keep using execv to check for the correct path and for the program to continue running after execv succeeds?
The exec family of functions do not kill your process. They replace the existing process image with the one you execute.
Basically, it works as if, that process (with its PID and associated kernel resources) remains the same, except all the code from the old image is removed and replaced by the code from the program that is then loaded into memory and initialized as if it were a new process altogether. The PID does not change, so if you want to create a child process with its own PID, you have to use another function.
The correct way to proceed is to fork first, and use exec* from the child process. This way you can use the wait function in the parent instance to wait for the child to terminate and take control back.
+--------------+ +--------------+ +----------------------+
|Parent process|+---fork()-->|Parent process|+---------wait()------------>|Parent process resumes|
+--------------+ + +--------------+ +----------------------+
| +
| |
| |
| +-------------+ +-----------------+ |
+----->|Child process|+--execv()--->|New process image|+--exit--+
+-------------+ +-----------------+
The various forms of exec() actually replace the current process image with the requested one. They do not spawn a new process. So you need to do it yourself, using fork().

Differences between fork and exec

What are the differences between fork and exec?
The use of fork and exec exemplifies the spirit of UNIX in that it provides a very simple way to start new processes.
The fork call basically makes a duplicate of the current process, identical in almost every way. Not everything is copied over (for example, resource limits in some implementations) but the idea is to create as close a copy as possible.
The new process (child) gets a different process ID (PID) and has the PID of the old process (parent) as its parent PID (PPID). Because the two processes are now running exactly the same code, they can tell which is which by the return code of fork - the child gets 0, the parent gets the PID of the child. This is all, of course, assuming the fork call works - if not, no child is created and the parent gets an error code.
The exec call is a way to basically replace the entire current process with a new program. It loads the program into the current process space and runs it from the entry point.
So, fork and exec are often used in sequence to get a new program running as a child of a current process. Shells typically do this whenever you try to run a program like find - the shell forks, then the child loads the find program into memory, setting up all command line arguments, standard I/O and so forth.
But they're not required to be used together. It's perfectly acceptable for a program to fork itself without execing if, for example, the program contains both parent and child code (you need to be careful what you do, each implementation may have restrictions). This was used quite a lot (and still is) for daemons which simply listen on a TCP port and fork a copy of themselves to process a specific request while the parent goes back to listening.
Similarly, programs that know they're finished and just want to run another program don't need to fork, exec and then wait for the child. They can just load the child directly into their process space.
Some UNIX implementations have an optimized fork which uses what they call copy-on-write. This is a trick to delay the copying of the process space in fork until the program attempts to change something in that space. This is useful for those programs using only fork and not exec in that they don't have to copy an entire process space.
If the exec is called following fork (and this is what happens mostly), that causes a write to the process space and it is then copied for the child process.
Note that there is a whole family of exec calls (execl, execle, execve and so on) but exec in context here means any of them.
The following diagram illustrates the typical fork/exec operation where the bash shell is used to list a directory with the ls command:
+--------+
| pid=7 |
| ppid=4 |
| bash |
+--------+
|
| calls fork
V
+--------+ +--------+
| pid=7 | forks | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash | | bash |
+--------+ +--------+
| |
| waits for pid 22 | calls exec to run ls
| V
| +--------+
| | pid=22 |
| | ppid=7 |
| | ls |
V +--------+
+--------+ |
| pid=7 | | exits
| ppid=4 | <---------------+
| bash |
+--------+
|
| continues
V
fork() splits the current process into two processes. Or in other words, your nice linear easy to think of program suddenly becomes two separate programs running one piece of code:
int pid = fork();
if (pid == 0)
{
printf("I'm the child");
}
else
{
printf("I'm the parent, my child is %i", pid);
// here we can kill the child, but that's not very parently of us
}
This can kind of blow your mind. Now you have one piece of code with pretty much identical state being executed by two processes. The child process inherits all the code and memory of the process that just created it, including starting from where the fork() call just left off. The only difference is the fork() return code to tell you if you are the parent or the child. If you are the parent, the return value is the id of the child.
exec is a bit easier to grasp, you just tell exec to execute a process using the target executable and you don't have two processes running the same code or inheriting the same state. Like #Steve Hawkins says, exec can be used after you forkto execute in the current process the target executable.
I think some concepts from "Advanced Unix Programming" by Marc Rochkind were helpful in understanding the different roles of fork()/exec(), especially for someone used to the Windows CreateProcess() model:
A program is a collection of instructions and data that is kept in a regular file on disk. (from 1.1.2 Programs, Processes, and Threads)
.
In order to run a program, the kernel is first asked to create a new process, which is an environment in which a program executes. (also from 1.1.2 Programs, Processes, and Threads)
.
It’s impossible to understand the exec or fork system calls without fully understanding the distinction between a process and a program. If these terms are new to you, you may want to go back and review Section 1.1.2. If you’re ready to proceed now, we’ll summarize the distinction in one sentence: A process is an execution environment that consists of instruction, user-data, and system-data segments, as well as lots of other resources acquired at runtime, whereas a program is a file containing instructions and data that are used to initialize the instruction and user-data segments of a process. (from 5.3 exec System Calls)
Once you understand the distinction between a program and a process, the behavior of fork() and exec() function can be summarized as:
fork() creates a duplicate of the current process
exec() replaces the program in the current process with another program
(this is essentially a simplified 'for dummies' version of paxdiablo's much more detailed answer)
Fork creates a copy of a calling process.
generally follows the structure
int cpid = fork( );
if (cpid = = 0)
{
//child code
exit(0);
}
//parent code
wait(cpid);
// end
(for child process text(code),data,stack is same as calling process)
child process executes code in if block.
EXEC replaces the current process with new process's code,data,stack.
generally follows the structure
int cpid = fork( );
if (cpid = = 0)
{
//child code
exec(foo);
exit(0);
}
//parent code
wait(cpid);
// end
(after exec call unix kernel clears the child process text,data,stack and fills with foo process related text/data)
thus child process is with different code (foo's code {not same as parent})
They are use together to create a new child process. First, calling fork creates a copy of the current process (the child process). Then, exec is called from within the child process to "replace" the copy of the parent process with the new process.
The process goes something like this:
child = fork(); //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail
if (child < 0) {
std::cout << "Failed to fork GUI process...Exiting" << std::endl;
exit (-1);
} else if (child == 0) { // This is the Child Process
// Call one of the "exec" functions to create the child process
execvp (argv[0], const_cast<char**>(argv));
} else { // This is the Parent Process
//Continue executing parent process
}
The main difference between fork() and exec() is that,
The fork() system call creates a clone of the currently running program. The original program continues execution with the next line of code after the fork() function call. The clone also starts execution at the next line of code.
Look at the following code that i got from http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("--beginning of program\n");
int counter = 0;
pid_t pid = fork();
if (pid == 0)
{
// child process
int i = 0;
for (; i < 5; ++i)
{
printf("child process: counter=%d\n", ++counter);
}
}
else if (pid > 0)
{
// parent process
int j = 0;
for (; j < 5; ++j)
{
printf("parent process: counter=%d\n", ++counter);
}
}
else
{
// fork failed
printf("fork() failed!\n");
return 1;
}
printf("--end of program--\n");
return 0;
}
This program declares a counter variable, set to zero, before fork()ing. After the fork call, we have two processes running in parallel, both incrementing their own version of counter. Each process will run to completion and exit. Because the processes run in parallel, we have no way of knowing which will finish first. Running this program will print something similar to what is shown below, though results may vary from one run to the next.
--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--
The exec() family of system calls replaces the currently executing code of a process with another piece of code. The process retains its PID but it becomes a new program. For example, consider the following code:
#include <stdio.h>
#include <unistd.h>
main() {
char program[80],*args[3];
int i;
printf("Ready to exec()...\n");
strcpy(program,"date");
args[0]="date";
args[1]="-u";
args[2]=NULL;
i=execvp(program,args);
printf("i=%d ... did it work?\n",i);
}
This program calls the execvp() function to replace its code with the date program. If the code is stored in a file named exec1.c, then executing it produces the following output:
Ready to exec()...
Tue Jul 15 20:17:53 UTC 2008
The program outputs the line ―Ready to exec() . . . ‖ and after calling the execvp() function, replaces its code with the date program. Note that the line ― . . . did it work‖ is not displayed, because at that point the code has been replaced. Instead, we see the output of executing ―date -u.‖
fork() creates a copy of the current process, with execution in the new child starting from just after the fork() call. After the fork(), they're identical, except for the return value of the fork() function. (RTFM for more details.) The two processes can then diverge still further, with one unable to interfere with the other, except possibly through any shared file handles.
exec() replaces the current process with a new one. It has nothing to do with fork(), except that an exec() often follows fork() when what's wanted is to launch a different child process, rather than replace the current one.
fork():
It creates a copy of running process. The running process is called parent process & newly created process is called child process. The way to differentiate the two is by looking at the returned value:
fork() returns the process identifier (pid) of the child process in the parent
fork() returns 0 in the child.
exec():
It initiates a new process within a process. It loads a new program into the current process, replacing the existing one.
fork() + exec():
When launching a new program is to firstly fork(), creating a new process, and then exec() (i.e. load into memory and execute) the program binary it is supposed to run.
int main( void )
{
int pid = fork();
if ( pid == 0 )
{
execvp( "find", argv );
}
//Put the parent to sleep for 2 sec,let the child finished executing
wait( 2 );
return 0;
}
The prime example to understand the fork() and exec() concept is the shell,the command interpreter program that users typically executes after logging into the system.The shell interprets the first word of command line as a command name
For many commands,the shell forks and the child process execs the command associated with the name treating the remaining words on the command line as parameters to the command.
The shell allows three types of commands. First, a command can be an
executable file that contains object code produced by compilation of source code (a C program for example). Second, a command can be an executable file that
contains a sequence of shell command lines. Finally, a command can be an internal shell command.(instead of an executable file ex->cd,ls etc.)

Resources