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.
Related
The output of the program are not obviously contents from the printf()s in teh code. Instead it looks like characters in irregular sequence. I know the reason is because the parent process and child process are running
at the same time, but in this program I only see pid=fork(), which I think means pid is only the id of child process.
So why can the parent process print?
How do the two processes run together?
// fork.c: create a new process
#include "kernel/types.h"
#include "user/user.h"
int
main()
{
int pid;
pid = fork();
printf("fork() returned %d\n", pid);
if(pid == 0){
printf("child\n");
} else {
printf("parent\n");
}
exit(0);
}
output:
ffoorrkk(()) rreettuurrnende d 0
1c9h
ilpda
rent
I focus my answer on showing how the observed output can result from the shown program. I think that it will already clear things up for you.
This is your output.
I edited it to use a good guess of what is parent (p) and child (c):
ffoorrkk(()) rreettuurrnende d 0\n
cpcpcpcpcpcpcpcpcpcpcpcpccpcpcppccc
1 c9h\n
pccpcpp
ilpda\n
ccpcpcc
rent
pppp
If you only use the chars with a "c" beneath, you get
fork() returned 0
child
If you only use the chars with a "p" beneath, you get
fork() returned 19
parent
Split that way, it should match what you know about how fork() works.
Comments already provided the actual answer to the three "?"-adorned questions in title and body of your question post.
Lundin:
It creates two processes and they are executed just as any other process, decided by the OS scheduler.
Yourself:
each time fork() is called it will return twice, the parent process will return the id of child process, and child process will return 0
Maybe for putting a more obvious point on it:
The parent process receives the child ID and also continues executing the program after the fork().
That is why the output occurs twice, similarily, interleaved, with differences in PID value and the selected if branch.
Relevant is also that in the given situation there is no line buffering. Otherwise there would be no character-by-character interleaving and everthing would be much more readable.
So, I've been trying to understand forks, and although I understand the basics (ie. another process gets created with a copy of the original data when we use fork()), I can't really grasp actually doing things with these processes that are created.
For example: I have to write a program that will call fork() twice to create 4 processes in total. When one process is created I have to print out the pid with getpid(). After printing out four ID's, my program is supposed to print a single letter 10 times.
For example, parent 1 will print 'A', child 1 will print 'B', child 2 will print 'C' and the parent of that will print 'D'. To do this, I have to use putchar(ch); and flush the output with fflush(stdout).
This means the output will look like this:
Process created, ID: 3856
Process created, ID: 3857
Process created, ID: 3858
Process created, ID: 3859
AAAAAABBBBBBBCDCDCDCDCDCDCBBBDCDCAAAADCD
So far, I've gotten the four processes to print with this code:
int main(void) {
pid_t child1, child2;
child1 = fork();
child2 = fork();
printf("Process created. ID: %d\n", getpid());
}
But I don't know how to use wait() to have everything print out randomly, after I have printed the ids.
To get everything I need to print out to be a "random mess," what should I do? Should I call functions like this?
// in main
for(int i = 0; i < 10; ++i) {
char_parent1();
char_child1();
char_parent2();
char_child2();
}
return 0;
}
void char_parent1()
{
putchar('A');
fflush(stdout);
}
void char_child1()
{
putchar('B');
fflush(stdout);
}
// and so on for char_parent2() and char_child2()
In that case, if my professor says I have to basically print things out concurrently and randomly, then why should I be using wait()?
Each process needs to know which letter it is supposed to print. That means you have to analyze the values in child1 and child2. For example, one process has two zeros; it might print D.
Arguably, each process needs to know whether it is a parent or not. If it is not a parent, it can simply exit after printing 10 copies of its letter, each followed by a fflush(). If it is a parent, after waiting for its children to die, it should exit. This means that the original process will exit last. It could usefully output a newline after its last child has died. You might or might not print diagnostic information about dead children as you go.
How we can get this process with this condition??schema of process?
int main (int argc, char **argv) {
int i;
int pid;
for (i= 0; i < 3; i++) {
pid = fork();
if (pid < 0) break;// with this condition i dont understand??
}
while (wait(NULL) != -1);
fork() splits a process in two, and returns 0 (if this process is the child), or the PID of the child (if this process is the parent), or -1 if the fork failed. So, this line:
if (pid < 0) break;
Says "exit the loop if we failed to create a child process".
The diagram is a little confusing because of the way the processes (circles) correspond to the fork() calls in the loop. The three child processes of the main process are created when i is 0, 1, and 2 respectively (see the diagram at the bottom of this post).
Since the loop continues in both the parent and the child process from the point fork was called, this is how the forks happen:
i == 0: fork is called in the original parent. There are now two processes (the top one, and the left one).
i == 1: fork is called in the two existing processes. New children are the leftmost child on the second layer from the bottom, and the middle child on the third layer from the bottom. There are now four processes
i == 2: fork is called in all existing processes. New children are all remaining nodes (the bottom node, the two rightmost nodes in the second layer from the borrom, and the rightmost node in the third layer from the bottom)
i == 3: All 8 processes exit the loop
Here is the diagram again, with numbers indicating what the value of i was in the loop when the process was created:
-1 <--- this is the parent that starts the loop
/ | \
0 1 2
/ \ |
1 2 2
|
2
To understand your diagram you must rely on the behavior of fork: it splits the process in two, creating another process identical to the first (except for the PID) in a new memory location.
If you call it in a loop that's what happen:
When i=0 the first process will be split, creating another process that will start running from exactly this point on (so will skip the first loop). Focusing on the first process, it will continue the loop, generating another process when i=1. The second process, thus, will start from i=1, so will skip the first two loops. The first process will be split last time for i=2. The last copy created, however, will start running from i=2, so it will exit the loop and will not generate anything.
The first copy created will start the loop from i=1, generating two process, while the second copy will start from i=2, generating only one copy.
You can continue this reasoning and understand the rest of the diagram.
As others pointed out, if (pid < 0) is just a check to see if there are errors and does not modify the logic of the code.
fork returns -1 if the fork call failed. it returns the pid in parent and 0 in the child. The condition you're looking at doesn't really matter to the functioning of the code; it's just saying if there's an error with fork then exit the loop. If there's no error in the fork call then the process tree in your diagram will be built.
The reason why is that the same loop will continue running in the child processes. So the children will also continue to fork based on the value of i at the time fork was called.
fork return -1 on error, and 0 or positive else, so the line if (pid < 0) break; says "if there was error, exit from the loop".
Assuming that there is not error, it's something like:
At the beginning, i=0, and you have one process. let's call it p0.
In the line fork();, p0 creates another process. let's call it p1.
In everyone of them, we have i++ (so now i is 1), and we are iterating the loop again.
p0 and p1, separately, have a fork(); command, so everyone of them creates another process. let's call the new processes p2 and p3.
Now, in every process, we have i++, that set i to be 2, and we run the loop again.
Everyone of the 4 processes we have, run the line fork();, and creates a new process. so now we have also p4,p5,p6,p7.
Every process increase its i to 3, and then, since the loop condition is now false, the loop finally ends.
Now, the 8 process arrive (separately) to the next line.
(In fact, every iteration double the number of processes, so if you change the 3 to, for example, 15, you will have 2^15 processes at the end.)
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.
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 every time I call fork later in the program, these print statements are 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 15 total children of the initial executable. Each process prints it's 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" repeating seemingly infinitely, and the file ofile is of seemingly proper format, but far far too large for what I think my program should be doing.
Any help would be greatly appreciated.
I am not sure why the fputs to stdout would be executed for the children, and don't have a Unix box to hand to verify/test.
However, the following jumps out:
int depth = *argv[2];//depth of the process tree
int arity = *argv[3];//number of children each process should have
You are taking the ASCII codes of the first character in argv[2] and argv[3] as your depth and arity, so your code is trying to spawn 50^51 processes instead of 2^3.
What you want is:
int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have
Once you fix this, bleh[0] = depth and its twin will also need correcting.
edit Although this is not a problem right now, you're cutting it pretty close with the length of some of the things you're sprintfing into obuf. Make some of the messages just a little bit longer and Kaboom! At the very least you want to use snprintf or, better yet, fprintf into the file directly.
edit I've just realised that fork, being an OS function, most probably isn't aware of internal buffering done by C I/O functions. This would explain why you get duplicates (both parent and child get a copy of buffered data on fork). Try fflush(stdout) before the loop. Also fflush(ofile) before every fork.
You have 2 errors in your code :
1)
int depth = *argv[2];//depth of the process tree
int arity = *argv[3];//number of children each process should have
With this code you are getting the first char of the strings argv[2] and argv[3].
A correct code must be like that :
int depth = atoi(argv[2]);
int arity = atoi(argv[3]);
2)
bleh[0] = depth;
fputs(bleh, stdout);
bleh[0] = arity;
fputs(bleh, stdout);
You can do something like that bleh[0] = (char) depth; but you'll just keep the first byte of your integer and its not that you want to do i guess, if you want to print the whole integer, simply use :
printf("%d\n%d", depth, arity);
I just tryied your code with those modifications and it seems to work well :)
Anhuin
You can't print out numbers using that code at the start of your function. It's probably invoking undefined behavior by passing a non-string to fputs(). You should use sprintf() (or, even better, snprintf()) to format the number into the string properly, and of course make sure the buffer is large enough to hold the string representation of the integers.
Also, you seem to be emitting text to the file, but yet it is opened in binary mode which seems wrong.