Understanding how fork() and wait() work together - c

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.

Related

How do I consistently find the PID of a program OR how do I send the kill shortcut to my terminal from a C script?

I'm answering my own question here because all of the other threads talking about this gave generally inefficient solutions to this problem[refer to title].
The most logical way to find the PID of a program is with getpid. However for some reason getpid command always gives you the PID that is two numbers behind the actual program ID it's about to be assigned. I'm sure someone more familiar with the linux kernel will be sure to explain why I'm an idiot in the comments below, so the reasoning for the -2 pid is probably down there.
Anyway, here's a reverse engineered c script(from MTU) that gives you the PID of the program.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
void main(void)
{
pid_t pid;
char fetch[50];
pid = getpid();
int pid2=pid+2;
sprintf(fetch, "echo hello world! my PID is %d", pid2);
system(fetch);
}
However for some reason getpid command always gives you the PID that is two numbers behind the actual program ID it's about to be assigned.
Well, getpid returns the PID of the current process.
How can it return the PID of a new process that doesn't exist yet? How could it possibly know?
The current process has a process ID. When you call system, it creates a child process, with its own process ID. Presumably the child process then creates another child to execute the command you passed to system.
By default the first child's PID will be the current process PID + 1. And the second child's PID will be the current process PID + 2. However, if either of those IDs are already in use (or you hit the maximum value of a pid_t and wrap around), this brittle logic will break completely.
If you want to get a child process' PID, call fork directly:
pid_t childpid = fork();
if (childpid < 0) {
perror("failed to fork");
exit(1);
}
if (childpid == 0) {
/* this path executes in the child process */
exec_command_in_child();
} else {
/* this path executes in the parent */
wait_or_kill_or_something(childpid);
}

What happens to active child processes when you fork a parent, do all active processes create another process ? Fork();

Bellow is the code of what is going on , and here is an image of what am i trying to do , any help would be appreciated.Trying to draw the diagram of all the processes
Code:
for(i=0;i<2;i++){
int pid = fork();
if(pid == 0){
fork();
printf("\tA\n");
}
else{
printf("\tB\n");
}
}//for
printf("\tC\n");
return 0;
}
This is the code of the program
This is the output of the program
Mainly missing from your diagram is in the block Child1 as well as Child1.1 a second run through the for loop, since these children are still inside the loop and their i is initially also 0.
On the other hand, the C=3 in Parent is wrong because C is only printed once at the end, not in the loop.

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.

Waiting for processes in C

I've been reading the documentation on wait() and waitpid() and I'm still somewhat confused about how they work (I have gathered that wait(&status) is equivalent to waitpid(-1, &status, 0);). Below are some small snippets of code I'm working on. Please help me understand whether these snippets are written properly and if not then why not.
Goal 1: Reap all zombie children.
int reapedPid;
do {
reapedPid = waitpid(-1,NULL,WNOHANG);
} while (reapedPid > 0);
What I'm trying to do here is iterate through all the children, reap the child if it's finished, let it keep going if it's not, and when I run out of children then reapedPid == -1 and the loop exits. The reason I'm confused here is that I don't see how waitpid() is supposed to know which children have already been checked and which have not. Does it do any such check? Or will this approach not work?
Goal 2: Wait for all children to finish.
int pid;
do {
pid = wait(NULL);
} while (pid != -1);
Here I don't care what the resulting status is of the children - this should just keep waiting for every child process to finish, whether successfully or unsuccessfully, and then exit. I think this code is correct but I'm not sure.
Goal 3: Fork a child and wait for it to finish.
int pid = fork();
if (pid < 0) {
// handle error.
}
else if (pid == 0) {
// execute child command
}
else {
int status;
int waitedForPid = waitpid(pid,&status,0);
assert(waitedForPid == pid);
}
Here I'm just trying to fork the process and have the parent wait for the child to finish. I am not entirely sure if I should be passing in the 0 option here but it seemed like WNOHANG, WUNTRACED, and WCONTINUED were not really relevant to my goal.
It is the kernel's job to keep track of processes. Keeping track of dead processes is trivial. The kernel can tell which child processes have died but not yet been waited for, and will return one of those dead children on each call, until there are none left to report on. (Because of the WNOHANG option, there might still be children left to wait for, but none of the remaining children are dead, yet.)
This second loop is also fine and almost equivalent to the first. The difference is that it will hang waiting for all the children to die before returning the -1.
This third fragment is fine; the assertion will be true except in extraordinary circumstances (such as another thread in the program also waited for the child and collected the corpse). However, if you somewhere launched another process and let it run in the background, you might be collecting zombies, whereas with a modification of the other loops, you can collect the zombies and still wait for the correct child:
int pid = fork();
if (pid < 0)
{
// handle error.
}
else if (pid == 0)
{
// execute child command
}
else
{
int status;
int corpse;
while ((corpse = waitpid(-1, &status, 0)) > 0)
if (corpse == pid)
break;
}
For most of these, you should be able to easily code up some example programs and verify your understanding.
Goal 1: Reap all zombie children.
The reason I'm confused here is that I don't see how waitpid() is supposed to know which children have already been checked and which have not. Does it do any such check?
Once a child has exited, it can only be waited on once. So your loop will only get the exit status for child processes that have not yet been waited on (zombies).
For Goals 2 and 3, again, I would consider it a required exercise to code up an example to see how it works. For #2, I would instead suggest that your code should always keep track of all forked children, so that it can know exactly who to wait on. Your code for #3 looks good; no options are required. Remember to use the WEXITSTATUS and friends macros to get information from the status.
See also:
Waiting for all child processes before parent resumes execution UNIX

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;
}

Resources