C: printf (with fork()) - c

In the next code:
int i = 1;
fork();
i=i*2;
fork();
i=i*2;
fork();
i=i*2;
printf("%d\n", i);
Why 8,8,8,8,8,8,8,8 is printed, and not 1,2,2,4,4,8,8,8? fork() duplicate the process, and print the i before each fork. What I miss?

Given the code shown, you should be seeing eight lots of 6 (you wrote i = i + 2; instead of i = i * 2; for the last computation.
Since each process follows the same code path, each process will produce the same result.
To get the result you expected, you'd have to track whether each fork() yielded the parent or child process:
int i = 1;
if (fork())
{
i=i*2;
if (fork())
{
i=i*2;
if (fork())
i=i*2; // + --> *
}
}
printf(|%d\n", i);
I'm assuming there are no problems with the fork() operation. It is also interesting to note that you could invert any or all of the conditions and end up with the same result.

Because fork continues to execute the code as it goes downwards. So each of the processes will run through the i = i * 2 each time as they spawn off more children. Making it what you get and not what you expected (i.e. it doesn't jump to the end of the block once forked).
Info on fork: http://www.csl.mtu.edu/cs4411/www/NOTES/process/fork/create.html

Each new process gets a copy of the stack of the parent, so immediately after calling fork(), both parent and child have the same value for i -- but they don't have the same stack, just a copy... so changing i's value in one process has no effect on the other.
If you want two parallel pieces of code to share the same memory, either use threads (and memory that's in the heap, not on the stack), or use an explicit shared memory region.

Related

Process tree / Number of processes for fork()

I want to know the number of processes created for the below code. I got to know from my instructor the answer is 41 but I am unable to follow the same. Please explain the same with a process tree.
void main() {
for (i=0;i<2;i++){
fork();
if(!fork()) {
execl("/bin/ls","ls",NULL);
fork();
}
fork();
}
fork();
}
This looks like a homework question. If we would draw a process tree for you, you might get some points now, but you will not learn how to analyze a program, and this may hurt you later. You will learn more by understanding how the program works. (Of course, this program is an academic example and not very useful except for learning.)
I suggest to mark the fork calls with letters.
int main(void) {
for (int i = 0; i < 2; i++) {
fork(); /* A */
if(!fork()) { /* B */
execl("/bin/ls","ls",NULL);
fork(); /* C */
}
fork(); /* D */
}
fork(); /* E */
}
Take paper and pencil, write down what happens and draw a tree using the loop counter and the marked fork calls.
Example:
The program runs a loop for two cycles (0 and 1), the loop continues in all processes.
In parent P, loop cycle 0, fork A will create child 1.
P -(0,A)-> 1
Still in loop cycle 0, both P and 1 will run the fork B inside the condition, creating a new child each.
P -(0,B)-> 2, 1 -(0,B)-> 3.
Think about the meaning of the condition and decide which processes run the conditional block.
Think about what happens after execl, e.g. process x executes ls, resulting in ...
Some processes (name them) will reach D and create a child each, all will continue with loop cycle 1...
etc.
To see what happens you could add some output after every fork to display what happens: which loop index, which fork, is the process parent or child of this fork, PID, parent PID. And before the execl display which PID is about to call it. (Note that buffered output like printf may show unexpected behavior in combination with fork, so it might be better to use sprintf and write.) Running the program will produce output that could help you to draw a process tree. It is even possible to format the output in a way that a tree could be generated automatically using graphviz or PlantUML. All these are advanced topics.

Understanding fork() order in C

So I have this program I'm trying to understand, its from an old exam but I just cant get a grip of it. How do I know the order of the forks and how the variables are changed?
static int g = -1;
int main(int argc, char *argv[])
{
int v = 0;
pid_t p;
while (v++ < 6)
if ((p = fork()) < 0) {
perror("fork error");
return 1;
} else if (p == 0) {
v++;
g--;
} else {
g++;
v+=3;
if (waitpid(p, NULL, 0) != p) {
perror("waitpid error");
return 1;
}
}
printf("mypid = %d parentpid = %d p = %d v = %d g = %d\n",
getpid(), getppid(), p, v, g);
return 0;
}
Each call to fork generates its own process with its own variables, which are copied at the time of the call (logically; optimization may change when the actual copy happens, but not in a way that'll change the outcome).
So when you enter the loop, v gets incremented to 1, then you fork. At this point the parent process has g=-1, v=1, p= and the new child has g=-1, v=1, p=0. The parent then drops into the else case, incrementing g to 0 and v to 4 and then waiting for the child to complete, whereas the child drops into the "else if (p == 0)", increments v to 2, decrements g to -2, and goes around the loop again.
From there, you've hopefully now got enough information to follow the logic as the next two child processes get forked off, finish off the loop, and print their respective results. When they do, the first child will also come to the end of its waitpid with v=6, drop out of the loop, and print its results.
At this point, the parent will unblock, go around the loop one more time (forking off one more child along the way), and (once that child has completed) drop out of the loop.
The call to fork() both starts a new process and continues the old one. If there is some kind of error, it returns an error value. All errors and only errors are negative numbers. This is what the first if block checks.
In the new process, fork() returns 0. The branch that increments v and decrements g is therefore called only in the child process, not the parent.
In the original process, the fork() function returns the process identifier (PID) of the daughter process, which is a positive integer. (This will later be passed to waitpid(). Therefore, the branch that decrements v and increments g is only called in the parent process, not the child.
Each process has its own copy of v and g. (That’s the main difference between a process and a thread: threads share memory.) On a modern SMP operating system, what will happen is that the child process gets a copy of the parent’s memory map. but these refer to the same pages of physical memory until one process or the other writes to them. When that happens, a copy is made of that page of memory and both processes now get their own, different copies.
The way modern Linux kernels implement fork(), the child process will continue before the parent does. This made a significant difference to performance. Most programs that call fork() immediately have the child process call exec() to start a new program. That means it isn’t going to need its copy of the parent’s memory at all. (There is a newer, simpler way to start a different program in a new process now, posix_spawn().) The parent process, on the other hand, almost always keeps running and modifying its memory. Therefore, giving the child the chance to declare that it’s going to discard the memory it inherited means that the parent doesn’t need to worry about leaving an unmodified copy of any memory pages for its children, and the kernel does not have to go through the rigmarole of copy-on-write.
In practice, though, any decent compiler will keep both local variables in registers, so this issue will not arise.
On the next iteration of the loop, which only happens after the child process terminates, a new child process is spawned using the updated values of the parent’s variables. Each child process also continues to run the loop with the same values of v and g that it inherited from its parent.

Understanding fork() in for loop and usage of exit()

Hey I have a question regarding fork() and how it behaves in a for loop.
So following is asked from me:
Create a Parent Process that creates 10 child Processes each of them printing the actual i value in the for loop. Is this code correct?
int i;
for(i=0;i < 10;i++){
if(fork()==0){
print(i);
}
exit(0);
}
My understanding is that this snippet of code creates on every loop iteration a parent and a child, where the parent terminates directly and the child prints i;
So to have only one parent and 10 children each of them printing i, I should wrap the exit(0) like this:
int i;
int p;
for(i=0;i < 10;i++){
if((p=fork())==0){
print(i);
}
if(p > 0){
exit(0);
}
}
Can someone confirm or this if its right, or help me to get a better understanding if its wrong.
Thanks :)
The fork() call creates not a pair of new processes (parent, child), but leaves original process (parent) and creates one another process (child), so it "returns twice".
In your first snippet you really have only one parent. The only problem, it finishes on the very first iteration. :)
Look: i = 0, now we have only parent process (call it P).
P enters fork() and leaves it twice: in P (returning the PID of the child) and in the newly created child C0 (returning 0). Then, according to if statement, C0 prints 0, P does nothing. Then execution paths converges, and both P and C0 exit. Now we have no our processes at all.
Your second snippet's loop body can be rewritten as follows:
p = fork();
if (p == 0) {
print(i);
}
if (p > 0) {
exit(0);
}
Supposing fork() will not return negative number (error), these two if bodies are in fact just like then-else branches. They cause child process to print its number and old parent process to exit, so you got a waterfall of processes replacing one another in a sequence (most of them act exactly once as a child and then as parent).
You just need to rewrite it as such:
for(i = 0; i < 10; i++) {
p = fork();
if (p == 0) {
print(i);
exit(0);
}
// In fact, you should place waitpid(...) somewhere here,
// otherwise the child will become a so called zombie process
// after its termination.
// Only after parent termination they all will be
// finally recycled by init (PID 1) generally using up your system's
// resources for indefinite time
}
Now you have P that creates C0. C0 prints its number and immediately exits, while P just continues to the next loop iteration creating C1 that just like C0 prints its number and exits and so on. AFAIK it is what initially requested.
Please note that in real life you will have to somehow process the -1 return value that indicate some error in the fork() call (so in reality, in the second snippet rewritten by me there is a possibility that neither if statement will execute), I have omitted them for simplicity.

How to pass arguments to processes created by fork()

I want to create copies of a process using fork() in C.
I cant figure out how to pass arguments to the copies of my process.
For example,I want to pass an integer to the process copies.
Or I what to do, if I have a loop in which I call fork() and want to pass a unique value to processes (e.g. 0...N)
for (int i = 0; i < 4; ++i) {
fork();
// pass a unique value to new processes.
}
The nice part about fork() is that each process you spawn automatically gets a copy of everything the parent has, so for example, let's say we want to pass an int myvar to each of two child processes but I want each to have a different value from the parent process:
int main()
{
int myvar = 0;
if(fork())
myvar = 1;
else if(fork())
myvar = 2;
else
myvar = 3;
printf("I'm %d: myvar is %d\n", getpid(), myvar);
return 0;
}
So doing this allows each process to have a "copy" of myvar with it's own value.
I'm 8517: myvar is 1
I'm 8518: myvar is 2
I'm 8521: myvar is 3
If you didn't change the value, then each fork'd process would have the same value.
Local and global variables are inherently preserved across a fork(), so there's no need to "pass arguments". If you're calling a function in the forked process, you can do something like:
pid_t pid = fork();
if (pid == 0) {
funcToCallInChild(argument);
exit(0);
}
I'm late to respond, but here is how I do it:
const char *progname = "./yourProgName";
const char *argument1 = "arg1";
const char *argument2 = "arg2";
if (fork() == 0)
{
// We are the child process, so replace the process with a new executable.
execl(progname, progname, argument1, argument2, (char *)NULL);
}
// The parent process continues from here.
First, you fork() the process to create a new process. It still has the same memory space as the old one. fork() returns for both parent and child processes. If fork() returns zero, you are the child process. The child process then uses execl() to replace the process memory with one from a new file.
Notice that progname is given twice to execl(). The first is what execl() will actually try to run, the second is argv[0]. You must provide both or the argument count will be off by one. Progname must contain all the required path information to find the desired executable image.
I give two arguments in this example, but you can pass as many as you want. it must be terminated with NULL, and I think you have to cast it as (char *) like I show.
This approach gives you a fully independent process with arguments and a unique pid. It can continue running long after the parent process terminates, or it may terminate before the parent.
You can use clone() (which is actually used by fork() itself). It lets you pass an arg to your entry function.
http://linux.die.net/man/2/clone
See the exec() family of functions.
EDIT: If you're trying to initialize copies of the same program as the base process, just continue using variables as suggested by duskwuff.

working of fork in c language [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
Now I have a problem in understanding the working of fork() system call.
I write a code which is following :
#include<stdio.h>
int main()
{
int a, b;
b=fork();
printf("\n the value of b = %d",b);
}
The output of this code is following :
Now I don't understand why the output is like this ?
After that i just add a line to my code and output is completely different.
my code is following:
int main()
{
int a, b;
b=fork();
When i run the code the output is following
2389my name is manish
the value of b = 0
Now I'm totally confused about the working of fork() call.
My question are following:
How fork() works?
Where the control goes after the fork() call?
Can any body explain why the outputs of codes written in problem?
Why the output of b occurring at different places means in first code
the output of b = 2260 is just before the output b = 0 while the value of b = 2389 is not just before the b = 0?
Please explain me the working of fork in the code written in the problem so that I can learn it properly .
It might help to first understand why the word fork was used to name this function. Ever heard of a "fork on the road?" At a fork, the process has to split paths.
First there is a single process executing normally until you reach the fork call. When fork is called, a new process is created, which is identical in virtually every way as the original process, except for the return value of the fork function. The newly created process is called the child process, and hence the process that spawned it is referred to as the parent process.
Since you'd want to perform different tasks for each branch of the fork, it necessitates that you be able to distinguish the child process from the parent process. That's where the return value of fork comes in: fork returns the process id (pid) of the child (the newly created process) to the parent; it returns 0 to the child. Also, should the execution of fork go wrong, the return value is -1.
In your code, you don't distinguish between the child and parent process, so both processes run the entire code that follows after the fork call.
//what the child process looks like after fork is called
int main()
{
int a, b;
b=fork(); // <-- current line of execution: 0 is returned to b
printf("\nmy name is manish\n");
printf("\n my name is anil\n");
printf("\n the value of b = %d",b);
}
// what the parent process looks like after fork is called
int main()
{
int a, b;
b=fork(); // <-- current line: child process id is returned
printf("\nmy name is manish\n");
printf("\n my name is anil\n");
printf("\n the value of b = %d",b);
}
As you can see, both processes have the same code following the fork, hence the output is repeated. Perhaps if you want the parent process to output Manish and the child to output Anil, then you can do something like:
int main()
{
pid_t b; // note that the actual return type of fork is
// pid_t, though it's probably just an int typedef'd or macro'd
b = fork();
if (b == -1) perror("Fork failed");
else if (b > 0) {
printf("My name is Manish\n"); // parent process
else
printf("My name is Anil\n"); // child process
printf("The value of b is %d\n", b);
return 0;
}
Finally, the last comment that must be made is that in your code, the output appears to have been executed first by one process in its entirety and then the other process in its entirety. That may not always be the case. For example, the operating system might allow the parent to execute the 'manish' output, then make this process wait, and handing the cpu over to the child process, which then executes 'manish'. However, the child process may continue and execute 'anil' and 'b' outputs, completing execution of the child process and thus returning execution back to the parent process. Now the parent finishes its execution by outputting 'anil' and 'b' itself. The final output of running this program may look something like:
my name is manish // executed by parent
my name is anil // child
the value of b = 0 // child
my name is anil // parent
the value of b = 2244 // parent
manish.yadav#ws40-man-lin:~$
Take a look at the man page for fork.
Also look at waitpid for proper handling of child processes by parent processes so you don't create zombies.
Edit: In response to your questions in the comments, I'll answer how you can simply run each process consecutively.
int main()
{
pid_t pid;
int i;
for (i=0; i<NUM_PROCESSES; i++)
{
pid = fork();
if (pid == -1)
{
perror("Error forking");
return -1;
}
else if (pid > 0)
{
// parent process
waitpid(-1, NULL, 0); //might want to look at man page for this
// it will wait until the child process is done
}
else
{
// do whatever each process needs to do;
// then exit()
doProcess(i);
exit(0);
}
}
// do anything else the parent process needs to do
return 0;
}
Of course, isn't the best code, but it's just to illustrate the point. The big idea here is the waitpid call, which causes the parent process to wait until the child process it just forked to terminate. After the child prcoess completes, the parent continues after the waitpid call, starting another iteration of the for loop and forking another (the next) process. This continues until all child process have executed sequentially and execution finally returns to the parent.
Fork creates a copy of your current process.
Both the original and the copy continue executing from the point at which fork() was called.
Because your code is executed twice, your print statements are also evaluated twice. In the copied process, the value of b is 0. In the original process, the value of b is the process ID of the copied process.
Once your processes start running concurrently, they will be scheduled independently by your operating system and thus you have no guarantees about when they will actually be run.
Forking is implemented by the OS. It basically creates a child process and starts running it after the fork().
The parent process receives the process id of the file process: b=fork(); b has the process id. The child process get a pid of zero.
(and 4) Because both process can either run in parallel or be time sliced, your output will vary.
You may want to check this out: http://en.wikipedia.org/wiki/Fork_(operating_system)
You'd better start from this.
Here you find explanation and code example.

Resources