Explain why fork causes the IF condition to behave differently. - c

I found this sample via a search.
At first glance I thought only the first fork() would be executed based on the IF condition, but actually both fork() calls get executed.
If the fork() command is changed to a simple boolean comparison like (x==10) then the IF conditions behave as expected.
What is it about the fork() that causes the IF condition to behave differently?
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pid_t whichone, first, second;
int howmany;
int status;
int x = 0
if ((first=fork())==0) /* Parent spawns 1st child */
{
printf("Hiya, I am the first child nd my id is %d\n", getpid());
sleep(10);
exit(0);
}
else if (first == -1)
{
perror("1st fork: something went bananas\n");
exit(1);
}
else if ((second=fork())==0) /* Parent spawns 2nd child */
{
printf("Hiya, I am the second child and my id is %d\n", getpid());
sleep(15); /* Sleep 15 sec, then exit */
exit(0);
}
else if (second == -1)
{
perror("2nd fork: something went bananas\n");
exit(1);
}
printf("This is the parent\n");
howmany=0;
while (howmany < 2) /* Wait twice */
{
whichone=wait(&status);
howmany++;
if (whichone==first)
printf("First child exited ");
else
printf("Second child exited ");
if ((status & 0xffff)==0)
printf("correctly\n");
else
printf("uncorrectly\n");
}
return 0;
Here is the output when executed. Notice that both fork() calls are processed.
> runtThis
Hiya, I am the first child, and my id is 31204
Hiya, I am the second child, and my id is 31205
This is the parent
First child exited correctly
Second child exited correctly

The first if detects if its running in the child. If it isn't, but fork() didn't fail (i.e., it didn't return -1), it's in the original process, which can then continue and call fork() again.
Not sure what the confusion is about.

The fork() function duplicates the current process and then returns in both processes. So, effectively, the fork() function returns twice.
In the new process, fork() returns with the value 0, which causes the relevant branch that prints "I am the child" to be taken.
In the original process, fork() returns a non-zero value, indicating either failure (if it is negative) or the process id of the new process (if it is positive). As this value is non-zero, the branch is skipped to the next else if and that test is performed until one succeeds.
In the parent process, none of the if/else if tests will succeed, but each of the fork calls causes a new process to be created in which the corresponding test succeeds and that creates the effects you noticed.

Related

Problem with Multiple Process Execution in c

I'm currently trying to create 2 child processes, and each child print something, the problem is one of the processes prints twice instructions of 'printf'.
here is the code:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t childPid[2];
if((childPid[0] = fork()) == 0)
printf("Hello I'm process one\n");
if((childPid[1] = fork()) == 0)
printf("Hello I'm process two\n");
return 0;
}
and here's the result after compiling & running:
Hello I'm process one
Hello I'm process two
Hello I'm process two
Any explanation of why the second process was executed twice please.
After the first fork call, the first child process continues to execute the rest of the program as well i.e. both the parent as well as the first child processes call fork again.
You just to exit the first child process, so that only the parent calls the second fork:
if((childPid[0] = fork()) == 0) {
printf("Hello I'm process one\n");
exit(0);
}
In the following code, you spawned a child process and there're 2 processes running, parent and child. A parent process can be identified by the return value of fork(), which prints a message but did NOT exit. That's why you see more one message on the next printf() result.
if((childPid[0] = fork()) == 0)
printf("Hello I'm process one\n");
Because neither of parent or child has exited, the following code would be excuted by 2 processes, both parent and child, which results in showing the same message twice.
if((childPid[1] = fork()) == 0)
printf("Hello I'm process two\n");
It is common that a child process executes an additional job and return whereas parent process continue its main flow. So, as a result, I prefer writing,
childPid[0]=fork();
if(childPid[0]<0)
{
// error
}
else if(childPid[0] == 0) // following code would be executed by child process only
{
printf("Hello I'm Child process two\n");
exit(EXIT_SUCCESS);
}

What's the difference between while(wait(NULL)){} and while(wait(NULL) > 0){} when using fork

I have the following piece of code:
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main() {
for(int i = 0; i <3; i++){
fork();
}
while(wait(NULL)){}
printf("Text\n");
return 0;
}
When I try to execute it, I receive a SIGKILL error, instead of getting 8 Text messages, from the fork call. However, If I change
while(wait(NULL)){}
to
while(wait(NULL) == 0){}
or
while(wait(NULL) > 0){}
I'm receiving 8 "Text" prints as expected.
Why isn't the program working in the first case? Isn't wait(NULL) loop or wait(0) loop supposed to wait until all child processes are finished executing?
Thanks for the help!
When you do this:
while(wait(NULL)){}
It's the same as:
while(wait(NULL) != 0){}
The wait function returns the child pid on success or -1 on error. So the return value will never be 0. This results in an infinite loop.
Doing this:
while(wait(NULL) > 0){}
Will loop as long as a child returns, and quit when -1 is returned.
while(wait(NULL) > 0) {}
Awaits for all child processes to finish, when no child process is left, a -1 is returned which breaks the while as -1 > 0 is false. Look at wait man page. Which in the first case is causing an infinite loop as -1 is evaluated as true.
A few things ...
You're doing fork in a loop but you're not separating the parent/child actions. That is, both finish the loop and both parent and child try to wait for completion.
You probably want to do the wait only in the parent.
wait(NULL) will suspend/wait for the next child to complete (i.e. not all of them). That's why you have to loop.
The return from wait is the pid of the child process that just exited [which is > 0]. If error, -1 is returned. If there are no more child processes to wait on, wait will return -1 (with errno set to ECHILD).
So, while (wait(NULL) > 0) is your best bet.
Adding some printf statements may help with your understanding:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int
main()
{
pid_t pid;
setbuf(stdout,NULL);
printf("parent: my pid is %d\n",getpid());
for (int i = 0; i < 3; i++) {
pid = fork();
if (pid != 0) {
printf("%d forked %d\n",getpid(),pid);
}
else {
printf("child: %d\n",getpid());
}
}
while ((pid = wait(NULL)) > 0) {
printf("%d: wait on %d\n",getpid(),pid);
}
printf("Text (from %d)\n",getpid());
return 0;
}
Here's the output:
parent: my pid is 469844
469844 forked 469845
child: 469845
469844 forked 469846
child: 469846
469844 forked 469848
469845 forked 469847
child: 469848
469846 forked 469849
Text (from 469848)
469845 forked 469850
child: 469849
child: 469850
Text (from 469849)
Text (from 469850)
child: 469847
469844: wait on 469848
469847 forked 469851
469845: wait on 469850
child: 469851
469846: wait on 469849
Text (from 469846)
Text (from 469851)
469844: wait on 469846
469847: wait on 469851
Text (from 469847)
469845: wait on 469847
Text (from 469845)
469844: wait on 469845
Text (from 469844)
pid_t wait(int *wstatus);
system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed.
The wait(&status) system call has two purposes. First, if a child of the calling process
has not yet terminated by calling exit(), then wait() suspends execution of the
process until one of its children has terminated. Second, the termination status
of the child is returned in the status argument of wait().
No when wstatus is NUll no status information well be stored!
on success, returns the process ID of the terminated child; on error, -1 is returned.
while(wailt(null)>0){
}
this means that we are waiting for all childrens to terminate in a success condition! upon first error we will exit the while and if the calling process have more childrens that didnt terminated yet, we will not wait for them which later , the terminated childs remains in a "zombie" state.
while(wailt(null)){
}
this means that even if errors happens on witing for one of the childs, (due to The options argument was invalid for example or any other reason see documentation), we will keep waiting untell the last child termination.
man7_wait()

C - Child Process Not Executing

[SOLVED]
So for this practice exercise I was assigned we are practicing process control. I'm simply wondering why it seems that my child process will never execute (when child_pid == 0). Any help on this issue would be greatly appreciated!
Also, safe_fork() is a function our instructor wrote in order to avoid students opening too many processes.
#include "safe-fork.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main(void) {
pid_t child_pid;
int pipefd[2];
int pipe_result;
int count;
pipe_result = pipe(pipefd);
if (pipe_result == -1) {
perror("pipe failure");
exit(1);
}
child_pid = safe_fork();
/*Parent Process*/
if (child_pid > 0) {
dup2(pipefd[0], STDIN_FILENO);
scanf("%d", &count);
if (count > 200) {
printf("Long enough!\n");
exit(0);
}
else {
printf("Too short!\n");
exit(1);
}
}
/* Child Process */
else {
dup2(pipefd[1], STDOUT_FILENO);
execl("/usr/bin/wc", "-w");
}
return 0;
}
Here is a suggestion, check for child_pid == 0 explicitly cause it could also be the case that your safe_fork() function failed, also check for those errors i.e child_pid < 0.
Add debug printf statements to check control flow if you already haven't and finally check if the execl call failed.
Also please have a look at this tutorial for creating pipes in C and using them to communicate between a parent and a child process. As I feel there are some issues with how you are handling those file descriptors. A possible reason that you can't see any output is that wc might still waiting for some input.
And another thing you might need to wait for the child process to complete/do something useful or actually be run before checking for its output. Check the other issues first before you worry about this.
Hope this Helps :)
Yes, But no. First you should carefully understand the meaning of fork().
fork(): creates a child process and it returns into TWO PROCESSES, with different return value in each. In parent, it always returns the number that OS has assigned for the newly created child's process id. At the same it returns in newly created child also, as child process will start executing the code copied from parent just after the fork() statement. In child fork always returns zero. So normally after a fork() system call, people check for returned value by fork to differentiate child process and parent process.
particularly in this case after a fork(), there will be two processes with same code and same program states(except both will have different value assigned in child_pid variable). In parent its a non zero value (which is corresponding to child's pid) and in child, its the value zero as the fork returns zero in child.
Now both processes will execute
if (child_pid > 0)
which is true only for parent so parent process will flow into 'if block' and is false for child so it will directly jump to else part and will execute the else block.
What if child_process id is zero?
OS will always assign a non zero value for a child so that fork() will work. And if you have somehow got child process id as zero then parent will fail to enter in 'if block' and will execute else block which is the same as child.

How to use fork() in an if statement

Can someone please explain to me what does fork() != 0 mean? From what I understand I think it means if fork is not false? Or if fork is true then.... I don't understand how Fork() can be true or false, seeing that it just creates a copy of a process into a parent and child. Also if a program where to say if (Fork() == 0) what would that mean?
#include "csapp.h"
int main(void)
{
int x = 3;
if (Fork() != 0)
printf("x=%d\n", ++x);
printf("x=%d\n", --x);
exit(0);
}
fork() returns -1 if it fails, and if it succeeds, it returns the forked child's pid in the parent, and 0 in the child. So if (fork() != 0) tests whether it's the parent process.
From man fork
Return Value
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child. On failure, -1 is returned in the
parent, no child process is created, and errno is set appropriately.
Assuming success, fork returns twice: once in the parent, and once in the child.
OK, I did the OP a disservice: I don't know where csapp.h comes from, but if it's this one then it isn't doing you any favours. I guess it is a thin wrapper on POSIX (eg. around fork()), but maybe works on other platforms too?
Because you mentioned fork() before Fork(), I assumed the latter was a typo, whereas it's actually a library function.
If you had been using fork() directly, it would be reasonable to expect you to check the manpage.
Since you're using a Fork() function provided by some library, that library really ought to document it, and doesn't seem to.
Standard (non csapp) usage is:
pid_t child = fork();
if (child == -1) {
printf("fork failed - %d - %s\n", errno, strerror(errno));
exit(-1);
}
if (child) {
printf("I have a child with pid %d, so I must be the parent!\n", child);
} else {
printf("I don't have a child ... so I must be the child!\n")
}
exit(0);
Let's try explaining it differently... When the function starts there's 1 process, this process has a int x = 3
Once you hit this line of code:
if (fork() != 0)
Now, assuming the fork() worked, we have two processes. They both have the same execution space, they both are going to run the same code (to a point), but the child will get its own copy of x to play with.
fork() will return a 0 to the child process, so from the child processes' prospective, the rest of the function is this:
printf(("x=%d\n", --x);
exit(0);
The parent process on the other hand, will get a valid value back from the fork() command, thus it will execute:
printf("x=%d\n", ++x);
printf("x=%d\n", --x);
exit(0);
What the output at this point will be is anyone's guess... You can't tell if parent or child will run first
But if we assume the parent hits the ++x is the next operation then the output is:
x=4
x=3
x=2
As both parent and child will hit the --x. (the parent's x was 4 after the ++x, will be 3 at the end. The child's x was 3, will be 2 at the end)
From fork() manual:
Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent
process. Otherwise, a value of -1 is returned to the parent process, no child process is created, and the global variable errno is set to indi-
cate the error.
After the code execution you have two execution threads. Into the if statement you have the parent process' thread and in else statement you have the child process' thread.
if ( fork() ) {
printf("I am the parent!\n");
} else {
printf("I am the child\n");
}
EDIT
For clarification purpose: fork starts a process, which has a thread, memory and may have other resources. I tried (it seems like that without success) to emphasize the flows of execution by adding the "thread" word.
However, by no means, one can say that "parent" relates to "thread" in "parent process' thread".
Of course, my answer could be improved but I think there are already enough good answers here.
Fork returns 0 for the child process and the process id of the child to the parent process. Hence commonly code has if(fork){ }else code. Which implies that the code inside the if is going to be executed only in a parent.
The better way to deal with it is
pid = fork()
if(pid){
// I am parent. Let us do something that only the parent has to do
}else{
// I am child. Let us do something only the child has to do
}
// This code is common to both
The child pid may be useful to wait upon later or to detach from the parent.
I recommend replacing the if with a switch because there are 3 possible results:
#include <sys/types.h>
#include <unistd.h>
pid_t pid;
switch ((pid = fork ())) {
case -1: /* error creating child. */
break;
case 0: /* I am the child process. */
break;
default: /* I am the parent process. */
break;
}

c fork,exec,getpid problem

I'm new to c language and Linux. I have a problem related to fork(),getpid()and exec()function.
I wrote a c program using fork() call the code of my program is following"
code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void fun()
{
printf("\n this is trial for child process");
}
int main (int argc, char const *argv[])
{
int i,status,pid,t;
if(pid=fork()<0)
{
printf("\nfailed to create the process\n");
}
if(pid=fork()==0)
{
printf("\n the child process is created");
fun();
exit(1);
}
while(wait(&status)!=pid);
return 0;
}
The out put of this program is following:
the child process is created
this is trial for child process
the child process is created
this is trial for child process
Now my questions are as follows:
Why the output of program showing same thing twice? The output supposed to be "child process is created this is trial for child process"
Why the output is not according to code ?
Can we have a program which has 4 processes and all the processes perform different task for example one process print "my name". One process print "my age", the other process print "my address ?
How to make multiple process in main function ?
How to control the execution of multiple process ?
what does the exec() function do? Can anyone please explain me the working of exec(), fork(), getpid() with a source code?
Please help this novice fellow.
Your code calls fork() multiple times:
if(pid=fork()<0) /* calls fork() */
{
...
}
if(pid=fork()==0) /* also calls fork() */
{
...
}
Each successful fork() creates a new child process. To make matters worse, the second fork() is called by both the parent and the first child.
If you're trying to create a single child process, you should call fork() just once:
pid_t pid; /* note the correct return type of fork() */
...
pid = fork();
if (pid < 0)
{
...
}
else if (pid == 0)
{
...
}
If you want to create multiple child processes, you can have the parent process call fork() in a loop.
As to questions like "what does exec do?", my advice is to learn how to use man and then come back with specific questions if there's something in the manpages that remains unclear.
In this code you are creating Three process not including your main process.
pid=fork()
is itself a statement , which forks a new process even though it is inside an if statement condition. After the first fork() call the remaining codes will be executed twice. so next fork call will be called twice. You have already created a new process.
fork returns zero to itself and its
process id to its parent
That is consider a process A forks B (not from your code)
pid = fork();
printf("pid is : %d",pid);
printf statement executes twice(one for A and one for B). For A it prints(A is parent)
pid is : 512 //some integer value
process id
and B prints
pid is : 0
So in your question
if(pid=fork()==0)
{
printf("\n the child process is created");
fun();
exit(1);
}
this is the second fork which is already executing twice. So each of this execution creates a new child process. For both childs pid value is 0. So your print statement executes, which is what you see in the output. But for both parents a pid value will be there and your if condition fails, so it wont print. These two childs are your second and third processes..So in short you create 3 processes along with the main process
The output is generated twice because you are forking twice:
if(pid=fork()<0) // Fork #1
{
printf("\nfailed to create the process\n");
}
if(pid=fork()==0) // Fork #2

Resources