I have to construct a tree of processes using fork() in C. I get a sequence of numbers from standard input (for example: 1 5 0 3) and those numbers tell me how many children each node has. If we take the example then the root process creates 1 child, then this one child creates 5 children of its own, then from those 5 children the first one doesn't create any children, the second one creates 3 of them and then we're done. After this is complete the root process calls pstree that draws out the tree.
Here is a picture of the example:
My question is how can I make new children from a specific node? One needs to create 0 new processes and the next one needs to create 3 of them. I don't know how to distinguish so that only that specific child makes new children and not all of them. Also I'm not sure how to use pstree, because the tree is normally already gone when pstree gets called. I know I can wait() for children to execute first but last ones do not have any children to wait for so they end too fast.
I've written code that creates the example. Need ideas how to generalize this for different inputs. Also can someone show me how to call pstree from this code because I can't seem to get it working.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid;
pid_t temppid;
pid_t temppid2;
int root_pid;
int status;
root_pid = getpid();
pid = fork(); // creates a child from root
if (pid == 0) { // if child
pid = fork(); // fork again (child#1)
if (pid != 0) { // if not child of child#1
temppid = getpid(); // get pid
if (getpid() == temppid) { // create child#2
pid = fork();
if (pid == 0) {
temppid2 = getpid();
if (getpid() == temppid2) { // create child#1
fork();
}
if (getpid() == temppid2) { // create child#2
fork();
}
if (getpid() == temppid2) { // create child#3
fork();
}
}
}
if (getpid() == temppid) { // create child#3
fork();
}
if (getpid() == temppid) { // create child#4
fork();
}
if (getpid() == temppid) { // create child#5
fork();
}
}
}
else {
// create another child from root
pid = fork();
if (pid == 0) {
// run pstree in this child with pid from root
}
}
while (1) {
sleep(1);
}
}
For pstree, the solution is simple - every process, after doing what it should, would go to sleep (for, say, a minute).
Then you can use pstree to see what's going on.
For forking the right number of times, it seems that the problem is with parsing the input, not with forking.
I'd start with writing code that reads the input and, instead of forking, just prints the tree of processes you want to create. Once you have this clear, it shouldn't be able to do the forks right.
For just testing the hierachy your app created:
Instead of placing a
return 0;
as last statement put a
while (1)
sleep(1);
This make the process run for ever until you press Ctrl-C.
After you started the app use another terminal and issue a pstree to inspect the process hierachy the app created.
To clean up (and if on linux) issue a killall <app name>.
My one suggestion is that you use the return value of fork to tell if your code is running in the child process or parent process.
Related
Last created First finished. My teacher said "Modify the code to processes finish in reverse order".
I just started with the exercise. I don't know how to implement so that the processes are executed backwards. My solution would be make a pid processes array and then use waitpid. Like this:
for(int i = num_processes;i>=0;i--){
waitpid(pid_list[i],NULL)
}
Teacher´s code
Finish order
thanks for helping!
The question I linked has been deleted due to it being too unclear, allow me to repost the answer here! Hopefully it helps you out!
//This is NODE 1
int pid = fork();
if(pid == -1){ // Something went wrong
//Handle error
}else if(pid == 0){ // This is the child process == NODE 2
int pid2 = fork();
if(pid2 == -1){ // Something went wrong
//Handle error
}else if(pid2 == 0){ // This is the child process == NODE 3
// Do whatever you want done on Node 3, and have it finish.
}else{ //This is NODE 2
wait(NULL); // Waits for node 3 to finish
}
}else{ //This is the parent process
//You can either do waitpid like you mentioned, or simply do wait NULL and it will wait for a process to finish
wait(NULL);
}
Of course if this were to go on with more nodes, I'd recommend a recursive approach since the code is exactly the same.
You mentioned the teacher showed you the code with the loop and the waitpid, the issue there is that if you want the parent to wait for all the processes, they should all hang from this same parent, instead of having a "tree-like" structure where every parent node waits for the child to finish before ending.
If you do indeed want one node to have all the children, you can do a loop where you create the forks like the one on the screenshot, exiting the loop whenever the result from the fork is a child process instead of the parent itself. Finally, waiting for all the children you created outside the loop, but only if you are the parent process. Something like this:
for(int i=0; i<N_NODES ;i++){
pid = fork();
if(pid == 0){
break; // You exit the loop so that the child doesn't create even more processes
}
}
if(pid != 0){
for(int i=0; i<N_NODES ;i++){
wait(NULL); //You can do wait NULL, or store the different pids when creating the fork and wait for individual pids.
// The issue here would be that you do not know which process finishes first, you can guess, but guessing is never good when programming
}
}
Hope this is what you wanted and I could help! ;)
Ok so I am going through past papers and I am stuck on a question about fork() function here is the diagram I am supposed to recreate using C.
I understand that fork() returns 0 to the child and the childs PID to the parent, but it's really hard to get my head around how exactly this all works.
I have come up with the following but I don't think it works:
while(fork() == 0) {
if (fork() == 0) break;
}
Any help would be appreciated.
Debugging your current code:
while(fork() == 0) {
This line creates a child process (we'll call it child process 1). The parent's process does not enter into the while loop. Child process 1 enters the loop.
if (fork() == 0) break;
This line is now being executed by child process 1, forking from it to create child process 2. If we are currently executing child process 2 (the 'child' of this fork call), we break. If we are executing child process 1, we will continue the next iteration of the while loop.
Now we have the following process tree:
. p
/
. child process 1
/
. cp2
Executing the while loop with child process 1 follows the same pattern as when we passed in parent, resulting in:
. p
/
. child process 1
/ \
. cp2 . cp3
/
. cp4
Solution:
Our end goal is to create 2 child processes, and continue forking from the second child process.
while (1) {
pid_t c1 = fork();
assert(c1 >= 0); // check fork error
if (c1 == 0) break; // don't make more children from c1
pid_t c2 = fork();
assert(c2 >= 0);
if (c2 > 0) break; // don't make additional children from parent
}
If you want to create two children processes from each child2 (and initial parent):
#define MAX 6
int value;
unsigned u = 0;
do{
if((value = fork()) == 0) // child1
break;
else if(value < 0) // error
break;
// parent
if((value = fork()) > 0) // parent
break;
else if(value < 0) // error
break;
// child2
u++;
}while(u < MAX);
if you don't want to set a MAX, use while(1).
Your program didn't create child1 for the first parent.
Write your code and add boxes for variable values on a sheet of paper and execute it by hand. Each time fork() is called:
make a photocopy of your sheet,
on the original give some unique non negative value for the return of fork,
on the copy give 0 to the returned value of fork,
continue to execute instructions on all sheet of paper in any order you want.
This is a good way to understand what will happen.
You are on the right track, in that you need to create new processes in a loop. But the way I think that image mean is that you should let the original parent keep creating processes inside an infinite loop, and the child (all siblings) do their work and exits.
There is also a problem with that image, in that a fork call doesn't really create two children, only one child and then the parent continues, which means that "child2` in that image is really all just the "parent".
So to implement something to create that tree I would do something like
for (;;)
{
int ret = fork();
if (ret == 0)
{
// In the child, "child1" in the image
// Do whatever is supposed to be done
exit(0); // Exit the child
}
else if (ret == -1)
{
// Error, handle it somehow
}
else
{
// In parent, what is called "child2" in the image
// Do something useful here...
// Then wait for the child to exit
wait(NULL);
}
// Let the loop iterate, to create a new "child1"
}
For an assignment, I'm supposed to create four processes in total, and print a letter multiple with each process. I'm supposed to call fork() twice to accomplish this.
I've been able to print the letters multiple times for each process. The problem arises in the second part of the assignment details. I'm supposed to print out the process ID for each process running before I print out the letters. The output should look like this:
Process ID: 123
Process ID: 124
Process ID: 125
Process ID: 126
AAAAABBBBBCCCCCDDDDD
I thought this could be accomplished by using this code:
pid_t child1, child2;
child1 = fork();
child2 = fork();
printf("Process created. ID: %d\n", getpid());
if(child1 == 0) { // print letters }
else if(child2 == 0) { //print letters }
else { // call waitpid and print more letters }
I thought since fork() splits at line child1 = fork(), then splits again at child2 = fork(), then goes to the next line, it would print everything out then hit the if-else statements. However, this is my output:
Process created. ID: 20105
Process created. ID: 20107
AAProcess created. ID: 20106
AAABBBProcess created. ID: 20108
BBCCCCCDDDDD
How can I ensure that my Process Created print statements execute first?
child1 = fork(); // Fork 1 here
child2 = fork(); // Fork 2 here after first fork .!!
Above fork will true that create four processes. But you are doing the second fork() with original parent and also by your first child. I guess this is not what you really need to do. You need to start three processes only with original parent.
Look at the given example : Here I create 2 child processes and all process count is 3 [With main] . Here I have tried to provide a reference solution with required output.
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <stdio.h> /* Input/Output */
#include <sys/wait.h> /* Wait for Process Termination */
#include <stdlib.h> /* General Utilities */
int main()
{
pid_t childpid1,childpid2; /* variable to store the child's pid */
/* now create new process */
childpid1 = fork();
if (childpid1 >= 0) /* fork succeeded */
{
if (childpid1 == 0) /* fork() returns 0 to the child process */
{
printf("1 : %d \n",getpid());
printf("AA");
}
else /* fork() returns new pid to the parent process */
{
childpid2 = fork();
if (childpid2 >= 0) /* fork succeeded */
{
if (childpid2 == 0) /* fork() returns 0 to the child process */
{
printf("2 :%d \n",getpid());
int stat;
waitpid(childpid1, &stat, 0);
printf("BB");
}
else /* fork() returns new pid to the parent process */
{
printf("3 : %d \n",getpid()); // This is the Original parent of ALL
int stat2;
waitpid(childpid2, &stat2, 0);
printf("CC");
}
}
}
}
return 0;
}
You have a synchronisation problem here: multiple processes share single resource (stdout) and are trying to print to it. You have two possible solutions here: either make your main process manager of the resource and make child processes send desired output to it (for example with pipes, this answer can give you a hint how to do it), or you need to use synchronisation with semaphores (here is a very good example).
This isn't in code review because I do not understand the full concept of the code to start with. If it should still be moved just let me know.
I have some code and I would like to explain my thoughts on it, and I am hoping someone can tell me where I am going wrong or getting confused at because I am still not fully sure what is occurring.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid, pid1;
pid = fork();
if (pid < 0) {
fprintf (stderr, “fork() failed\n”);
return(1);
}
else if (pid == 0) {
pid1 = getpid();
printf (“pid = %d\n”, pid); // A
printf (“pid1 = %d\n”, pid1); // B
}
else {
pid1 = getpid();
printf (“pid = %d\n”, pid); // C
printf (“pid1 = %d\n”, pid1); // D
wait (NULL);
}
return 0;
}
From what I understand, we have two process ID's, the parent (pid) and the child (pid1).
Once I call pid = fork(), I believe that the child is initiated and is given the id of 0, while the parent get's the ID of the child, let say 1337. So pid = 1337 and pid1 = 0.
So we skip the first if as no error has occurred (pid < 0), we skip the second if as well since pid does not equal 0, and then we enter the final if where C will print 1337 and D will pint out 0.
This then waits until the child is done, I think.
After that, I assume that the copied process (fork()) will then run the else if (pid == 0) but I am confused on why, because the pid is still 1337..
TLDR: If the third if should be executing first, then how do I get to the second if, but if this logic is all wrong please correct me.
A fork creates makes a (near-perfect) copy of the running process. One difference, as you surmised is the return value of fork() itself. So, assuming the fork works you have two processes executing the same code. One, the child, takes the if (pid == 0) ... path, while the parent takes the else... path. You have no information about the order in which the two processes do their work. Maybe the child goes first, maybe the parent, maybe half way through they take turns, maybe you have two processors and they run together...
Imagine you have this program written on a piece of paper and you are following along with your finger, sliding it down the page. When you get to the fork, take the paper to a copier, make a copy, put both pieces of paper on the table, put a your index finger from each hand on one of the pieces, move both your fingers, each sliding down their own sheet of paper.
Everything you said is not correct
after the fork() call is executed, the child and the parent process runs in parallel, both executing the code of the program that is there after fork(). The only difference would be the pid. The child will run the same program with the pid = 0, and the parent will run the same program with the pid = (pid of child). They seperate out, both having a copy of all the variables of the program, but a different copy of the pid variable.
pid is 0 in the child and the process ID of the child in the parent.
pid1 is set to the process ID of the current process. The value in the child's copy of pid1 is identical to the value of the parent's copy of pid.
On success, the PID of the child
process is returned in the parent’s
thread of execution, and a 0 is
returned in the child’s thread of execution.
p = fork();
I'm confused at its manual page,is p equal to 0 or PID?
I'm not sure how the manual can be any clearer! fork() creates a new process, so you now have two identical processes. To distinguish between them, the return value of fork() differs. In the original process, you get the PID of the child process. In the child process, you get 0.
So a canonical use is as follows:
p = fork();
if (0 == p)
{
// We're the child process
}
else if (p > 0)
{
// We're the parent process
}
else
{
// We're the parent process, but child couldn't be created
}
p = fork();
/* assume no errors */
/* you now have two */
/* programs running */
--------------------
if (p > 0) { | if (p == 0) {
printf("parent\n"); | printf("child\n");
... | ...
Processes are structured in a directed tree where you only know your single-parent (getppid()). In short, fork() returns -1 on error like many other system functions, non-zero value is useful for initiator of the fork call (the parent) to know its new-child pid.
Nothing is as good as example:
/* fork/getpid test */
#include <sys/types.h>
#include <unistd.h> /* fork(), getpid() */
#include <stdio.h>
int main(int argc, char* argv[])
{
int pid;
printf("Entry point: my pid is %d, parent pid is %d\n",
getpid(), getppid());
pid = fork();
if (pid == 0) {
printf("Child: my pid is %d, parent pid is %d\n",
getpid(), getppid());
}
else if (pid > 0) {
printf("Parent: my pid is %d, parent pid is %d, my child pid is %d\n",
getpid(), getppid(), pid);
}
else {
printf("Parent: oops! can not create a child (my pid is %d)\n",
getpid());
}
return 0;
}
And the result (bash is pid 2249, in this case):
Entry point: my pid is 16051, parent pid is 2249
Parent: my pid is 16051, parent pid is 2249, my child pid is 16052
Child: my pid is 16052, parent pid is 16051
If you need to share some resources (files, parent pid, etc.) between parent and child, look at clone() (for GNU C library, and maybe others)
Once fork is executed, you have two processes. The call returns different values to each process.
If you do something like this
int f;
f = fork();
if (f == 0) {
printf("I am the child\n");
} else {
printf("I am the parent and the childs pid is %d\n",f);
}
You will see both the messages printed. They're being printed by two separate processes. This is they way you can differentiate between the two processes created.
This is the cool part. It's equal to BOTH.
Well, not really. But once fork returns, you now have two copies of your program running! Two processes. You can sort of think of them as alternate universes. In one, the return value is 0. In the other, it's the ID of the new process!
Usually you will have something like this:
p = fork();
if (p == 0){
printf("I am a child process!\n");
//Do child things
}
else {
printf("I am the parent process! Child is number %d\n", p);
//Do parenty things
}
In this case, both strings will get printed, but by different processes!
fork() is invoked in the parent process. Then a child process is spawned. By the time the child process spawns, fork() has finished its execution.
At this point, fork() is ready to return, but it returns a different value depending on whether it's in the parent or child. In the child process, it returns 0, and in the parent process/thread, it returns the child's process ID.
Fork creates a duplicate process and a new process context. When it returns a 0 value it means that a child process is running, but when it returns another value that means a parent process is running. We usually use wait statement so that a child process completes and parent process starts executing.
I think that it works like this:
when pid = fork(), the code should be executed two times, one is in current process, one is in child process.
So it explains why if/else both execute.
And the order is, first current process, and then execute the child.