Not fully understanding fork for switch program output - c

I have been trying to understand the output of this program, but still I don’t quite get it.
main()
{
int pid, i;
pid = getpid();
for (i = 0; i < 25; i++)
{
switch (fork())
{
case 0:
if (pid % 2 == 0)
{
exit(0);
break;
}
default:
if (pid % 2 != 0)
{
exit(0);
}
}
}
printf("I am the process %d and my father is the process %d\n", getpid(), getppid());
while (wait(NULL) > 0) {}
return 0;
}
When I run this, it returns:
I am the process 11110 and my father is the process 26453
However, if you were to run the above code without both "% 2", it won't return anything.
I am very confused about this. The way I thought it would work (for the code without "% 2") is, for each for iteration:
the child (pid==0) would finish its process (killing the child process) and always break from the switch (not affecting the for loop)
the father/main process will wait until the child dies
next for iteration
Is the above approach correct? If so, how would it be with "% 2"?

Without % 2 you'd get:
switch (fork())
{
case 0:
if (pid == 0)
{
exit(0);
break;
}
default:
if (pid != 0)
{
exit(0);
}
}
Since pid is not 0, the parent would exit(0) immediately after the first fork(), so you won't see a print statement.

Related

How can I know when has execvp finished?

Im currently working on a class work in the Introduction to Operative Systems course, and we are asked to build a simple command interpreter in C.
For this interpreter, if we put '&' before a comand we execute it in the background and if we put ';' we execute it as usual (in the foreground). We are using fork and process management functions, so when we are in the parent process, if we typed ';' we simply wait until the child process (executing the comand, for example pwd), and if we put '&' we just dont wait and we break from the switch-case on where we are.
this is the code:
err = get_arguments(buf, n, arg, MAXARG); //if we type & sleep 5 we get the sleep 5 in the arg
id = fork();
switch (id){
case -1:
errore("fork");
break;
case 0: /* child process */
/* execute the command using execvp */
pid = getpid();
pid_parent = getppid();
if(buf[0] == '&') {
printf("-U------- Child: just created (PID %d - Parent PID: %d): now executing'%s ...' in the background...\n",
pid, pid_parent, arg[0]);
} else if(buf[0] == ';') {
printf("-U------- Umea naiz: sortu berria (PID %d - Parent PID: %d): orain '%s ...' exekutatzera aurreko planoan...\n",
pid, pid_parent, arg[0]);
}
execvp(arg[0], arg);
printf("-U------- Child (PID %d): i'm here only if an error has ocurred\n",
pid);
errore("exec");
break;
default: /* parent */
pid_child = id;
pid = getpid();
printf("-G------- Parent (PID %d): child process '%s ...' (PID %d) started \n",
pid, arg[0], pid_child);
if(buf[0] == '&') { // if we want to execute in the background
break; //break and don't wait for the child to stop
} else if(buf[0] == ';') { // if it's in the foreground
/* wait until child finishes */
pid_finished = wait(&status);
if ( pid_finished != pid_child) {
errore("wait");
} else {
if (WIFEXITED(status)){ // get the return code
child_return_code = WEXITSTATUS(status);
printf("-G------- Parent (PID %d): a child process (PID %d) has finished with the %d return code\n",
pid, pid_finished, child_return_code);
}
};
}
break;
}
}
for (n = 0; n < BUFSIZE; n++) buf[n] = '\0';
write(1, "prompt$ ", 9); //write the prompt again
When I write ; pwd for example, it obviously works great. How ever, i want the parent process to know when a child process that has been executed in the background, has finished. And when if happens, print it's id and the return code.
I don't know how to do this, because when execvp is used, the code that comes after it only gets executed when an error happens. So how can I know when this child process has finished in the background?
My code was in spanish so maybe something is spelled wrong, I tried my best.
Thank you so much!

C : Store PID in global variable

I am currently working on a school project and I wanted to store the PID of my process in the global array id, so that I can use it in another function :
int id[3];
int main(int agrc,const char* agrv[]) {
for(int i = 0; i < 3; i++) {
if((fork() == 0)) {
id[i] = (int)getpid();
printf("ID[%d] = %d\n",i,id[i]);
if(i != 3) {
printf("I am a wharehouse. PID = [%d] PPID = [%d]\n",getpid(),getppid());
whcode();
exit(0);
}
else if(i == 3) {
printf("I am the central. PID = [%d] PPID = [%d]\n",getpid(),getppid());
central_code();
exit(0);
}
}
}
sleep(2);
printf("ID[0] = %d\n",id[0]);
printf("ID[1] = %d\n",id[1]);
printf("ID[2] = %d\n",id[2]);
}
But when I run this the output of the last 3 prints is 0, where it should be the PID of each process. Why does this happen?
On the call to fork(), new process is created with separate virtual memory space. This child process will return from the call to fork with 0, so in your code, this child will go inside the if branch and assign to id[i] it's pid. But this assignment is happening in a separate process, with separate virtual memory, so it has no effect on the parents virtual memory space and the parent will not see any change in its array. That is why your code prints the zeroes.
If you want to print the pids of the children by the parent, use the return value of fork(), which in parent is the pid of the child process. Inside the for, use code such as this:
pid_t child_id;
switch (child_id = fork()) {
case -1:
//Fork failed, exit with error or something
break;
case 0:
//Child code
printf("ID[%d] = %d\n",i,id[i]);
if(i != 3) {
printf("I am a wharehouse. PID = [%d] PPID = [%d]\n",getpid(),getppid());
whcode();
exit(0);
}
else if(i == 3) {
printf("I am the central. PID = [%d] PPID = [%d]\n",getpid(),getppid());
central_code();
exit(0);
}
break;
default:
id[i] = child_id;
break;
}
By the way, you should really declare the id array as pid_t id[3], and when printing, print it as long. That for now is probably the most portable way to handle these things.

I try to create a process using 'fork'

I'm start to studying the fork. while using the fork, I have some problems.
I'm trying to create a single parent process with two child
and two child trying to make each three grandchild.
When I run my code, unlike my expectations, so many child and grandchild come out.
Here my code:
int main()
{
int i, j, rev;
for(i=0;i<2;i++)
{
if((rev=fork())<0) { printf("fork() error\n"); exit(-1); }
else if(rev==0)
{
printf("child %d %d \n",getpid(),getppid());
for(j=0;j<3;j++)
{
if((rev=fork()) <0) { printf("fork() error\n"); exit(-1); }
else if(rev == 0)
{
printf("grandch %d %d \n",getppid(),getpid());
exit(0);
}
}
}
}
printf("parent %d %d \n",getpid(),getppid());
exit(0);
}
How can I correct this code?
One important example before using fork() statements :
//Calculate number of times hello is printed.
#include <stdio.h>
#include <sys/types.h>
int main()
{
fork();
fork();
fork();
printf("hello\n");
return 0;
}
Number of times hello printed is equal to number of process created. Total Number of Processes = 2^n where n is number of fork system calls. So here n = 3, 2^3 = 8.
fork (); // Line 1
fork (); // Line 2
fork (); // Line 3
L1 // There will be 1 child process
/ \ // created by line 1.
L2 L2 // There will be 2 child processes
/ \ / \ // created by line 2
L3 L3 L3 L3 // There will be 4 child processes
// created by line 3
So if you are trying to make two child process and then three grand
child follow something of this sort:
What you should do is something like this for two child processes
if(fork()) # parent
if(fork()) #parent
else # child2
else #child1
After you create process , you should check the return value. If you don't , the second fork() will be executed by both the parent process and the child process, so you have four processes.
If you want to create n child processes , just :
for (i = 0; i < n; ++i) {
pid = fork();
if (pid) { //means pid is non-zero value, i.e, pid>0
continue;
} else if (pid == 0) {
break;
} else {
printf("fork error\n");
exit(1);
}
}
The section of code that runs for the child processes doesn't exit. As a result, they continue on to run more iterations of the outer loop which only the parent process is supposed to run, so they spawn more children.
You need to call exit, or better yet _exit, so that the children don't do that:
int main()
{
int i, j, rev;
for(i=0;i<2;i++)
{
if((rev=fork())<0) { printf("fork() error\n"); exit(-1); }
else if(rev==0)
{
printf("child %d %d \n",getpid(),getppid());
for(j=0;j<3;j++)
{
if((rev=fork()) <0) { printf("fork() error\n"); exit(-1); }
else if(rev == 0)
{
printf("grandch %d %d \n",getpid(),getppid());
_exit(0);
}
}
sleep(1); // stick around so the grandchild can print the parent pid
_exit(0); // exit the child
}
}
printf("parent %d %d \n",getpid(),getppid());
sleep(1); // stick around so the child can print the parent pid
exit(0);
}

How to create chain of processes in C?

I need to create 5 processes one being father of the second, grandpa of the third etc. All of them have to wait for each other to finish. I tried the approach with:
switch (pid = fork()) {
case 0:
printf("Child PID = %d\n", getpid());
printf("parent: =\%d\n", getppid());
return 0;
default:
break;
But I always get the same parent.
You need to use recursion.
For example:
void create_processes(int n) {
if(n == 0) return;
if(fork() == 0) {
int status;
// You're in the child process. Calling it recursively will have the
// child's PID as parent
create_processes(n - 1);
// Do work you need done before the child terminates
wait(&status);
// Do work you need done after the child terminates
}
}
Then call it like
create_processes(5);
Call a process myProcess that returns no type and takes an int as a parameter. Then...
void myProcess(int x)
{
if (x > 5) return;
if (x != 0)
myProcess(x - 1);
return;
};
int main()
{
int myvar = 5;
myProcess(myvar);
return 0;
}
It's done recursively.

Waiting for all child processes to be created - C

Let's suppose I have a code like the following
switch (fork()) {
case -1:
//error checking
break;
case 0:
//child code
break;
default:
int i;
for (i = 0; i < n; i++) {
switch (fork()) {
case -1:
//error checking
break;
case 0:
//exec
break;
default:
//parent that waits for all childs to be created
break;
}
}
}
How do I make the second parent process wait for all the other processes to be created exactly ...
I was told I had to make a loop but I don't know how to implement it exactly. Supposing there are n child processes.
I think you may have misunderstood the requirement slightly. The term 'second parent' doesn't make a lot of sense to me.
What makes most sense as a requirement is:
Parent process launches N children.
Each child does its appropriate stuff.
The parent process must then wait for all N children to complete.
Then it can report its own completion (or get on with other work, or ...).
In outline, you would then have:
int pid;
for (int i = 0; i < N; i++)
{
switch (pid = fork())
{
case 0:
be_childish(i);
/*NOTREACHED*/
break;
case -1:
// Print error report
break;
default:
printf("Started PID %d\n", pid);
break;
}
}
int status;
while ((pid = wait(&status)) > 0)
{
printf("PID %d exited (status 0x%.4X)\n", pid, status);
}
printf("All done!\n");
Note the /*NOTREACHED*/ comment. I assume that the child process exits from within the be_childish() function. The code could ensure no damage by including an exit(1); or perhaps _exit(1); or _Exit(1);. It is rather important that a child process does not continue the loop.

Resources