C: fork() child processes - c

According to the textbook I am reading, the code below creates N child processes that will exit with unique statuses.
/* Parent creates N children */
for (i = 0; i < N; i++)
if ((pid[i] = Fork()) == 0) /* Child */
exit(100+i);
Earlier in the textbook, it states that the following code will have 8 lines of output:
int main(){
Fork();
Fork();
Fork();
printf("hello\n");
exit(0);
}
This leads me to believe that there are 2^n child processes, where n is the number of times fork() is called. Is the reason the first code only produces N child processes (as opposed to 2^N) because the child exits every time, so by the time the subsequent fork() is called, it only operates on the parent process?

Every successful call to fork(), creates a new process.
In the first example, the children processes (the return value of fork() being 0) call exit();, which means they won't call the next fork().
In the second example, every children process continues forking.

When fork() is called it copies the parent data and starts executing from that point individually. So the execution of the parent or child is depend on the scheduling of process. Whichever process get cpu time will be executed whether it is child or parent. We have to take care that which code should run by which process(child or process).

Related

If you have a break inside an if statement that creates a child process in a for loop, does the loop no longer execute?

I am going through a code example in my textbook (dining philosophers problem) and in the main method, right before the return 0; statement, there is the block of code I've included below. This loop is supposed to create the philosophers each as a concurrent forked process. This means that each philosopher executes philosopher(i).
However, since right after the if statement, there follows a break, doesn't that mean only the first philosopher (i = 0) is created?
for (i = 0; i < N - 1; ++i)
if (fork() == 0)
break;
philosopher(i) ;
fork(2) "splits" the process calling it into two independent processes, the second a child of the first. In the parent process (the original process), it returns the PID of the child. In the child process, fork() returns 0.
So in your example, the loop only breaks in the child process, while continuing in the parent process to spawn the remaining philosophers.
The loop executes N - 1 times, spawning N - 1 child philosophers. After completing the loop, the parent process also calls philosopher(i), running the Nth and final philosopher.
fork() returns twice: in the parent with a non-zero value (a positive pid on success or a negative value on failure) and in the child with pid==0 (if the call succeeded).
if (fork() == 0) will break the loop in the child, so that the child continues at philosopher(i); (where the parent will also continue but only after all the loop iterations are over).
In other words,
for (i = 0; i < N - 1; ++i)
if (fork() == 0)
break;
philosopher(i) ;
tries to (fork() not checked against failure) run philosopher(i); in i=0 to i==N-2 incl. child processes and then runs it with i==N-1 in the parent.

Trying to understand forks and semaphores

What I am trying to do in my code is have a parent process that forks two children processes. This is how I've done it:
pid = fork();
if(pid != 1)
pid1 = fork();
The next thing I'm trying to do is switch between the processes continuously (from child to other child to parent, in that order) using semaphores. ie the child process will say A, the other child will say B, the parent will say C, the child will say D, and so on.
My two questions are:
Say you call sem_wait(sem) in a semaphore and the process blocks as it should. You then move on and the other process ends up calling sem_post(sem). Will the code following the sem_wait be immediately executed after the sem_post? ie does the execution "jump back" to the code after the sem_wait even if it doesn't come "next" in the program?
if(stuff){
a;
sem_wait(sem);
b;
}
c;
sem_post(sem);
Will b be executed even though it's "before" the post in terms of coming before it textually?
How can I identify the processes so that I may give one of them permission to execute? I have to confirm that a process is either child 1 , child 2 or parent before I give it permission to execute the code, but how can I tell? I tried to check using if statements (if(pid) != 0, if(pid() == 0 and if(pid1 == 0) assuming that the parent would have a return value of 0 for the the first fork and the children would have zero's for their respective forks) but this did not work. I checked their PID's and PPID's and they were all over the place).
All help is appreciated, thank you

Understanding fork() in for loop

I have a problem with understanding fork(). Can anybody explain me, what will this program print? Because I preparing for the exam and it is the typical question. Exactly in this case:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for(i = fork(); i < fork(); i++)
execlp(“echo”, “sono”, argv[0], 0);
system(“echo i+$i”);
}
For me, what is not understandable is this line
for(i = fork(); i < fork(); i++)
What does it mean? Thanks to all in advance.
Crunching the first full iteration from initialization through all processes finishing the first loop context, the following will happen:
1. Initializer
i is initialized from i = fork();
Process parent: i = pid(child1)
Child process child1: i = 0
Hitting the conditional test in each process something interesting happens
2. Process : parent
i < fork() will fork another child process, child2. If the returned pid(child2) is greater than pid(child1), the conditional test is met and the parent process continues to the loop body
3. Process : child1
i is zero from the initializer
i < fork() will fork a child process, child3. If the returned pid(child3) is greater than the value of i (which is zero, so it always will be), the conditional test is met and the child1 process continues to the loop body
4. Process: child2
Inherits i from parent, where i is pid(child1)
This process was spawned from evaluating i < fork(), so fork() will eval as 0. Therefore...
i < fork() will evaluate to be child1(pid) < 0, which will never be true. The conditional test fails, and the for-loop is terminated.
5. Process: child3
Inherits i = 0 from its parent, child1.
This process was spawned from evaluating i < fork(), so fork() will eval as 0. Therefore...
i < fork() will evaluate to be 0 < 0, which will never be true. The conditional test fails and the for-loop is terminated.
At this point, parent and child1 are the only two processes that make it to the loop body. The other two (child2 and child3) both failed their conditional checks. As a result, the following things happen:
6. The Final Steps
parent process is replaced with execlp("echo", "sono", argv[0], 0);
child1 process is replaced with execlp("echo", "sono", argv[0], 0);
child2 process invokes system("echo i+$i"); and terminates.
child3 process invokes system("echo i+$i"); and terminates.
This is important: At no time do any of the aforementioned processes evaluate the for-conditional more than once. Anything that succeeds the conditional test will be replaced with an execlp() process launch. Anything that fails the conditional test will leave the loop and terminate after the system() call. Therefore, once any process makes it past the conditional (either by success or failure) it will never fork() another process.
In other words, This is NOT a fork() bomb. If either the loop body or the suffix code past the loop forked another instance of this process, it would easily be a fork() bomb, but neither do so.
Note: it is possible that a pid-rollover, where process ids reset and start "filling in the holes", causes the first initial fork to introduce a child2 pid that is less than the child1 pid. If that happens, (however unlikely) the results would only change to this:
parent process invokes system(“echo i+$i”); and terminates.
child1 process is replaced with execlp("echo", "sono", argv[0], 0);
child2 process invokes system("echo i+$i"); and terminates.
child3 process invokes system("echo i+$i"); and terminates.
Not bloody likely, but then neither is winning a lottery, and people think it will happen to them all the time.
that code is incredibly twisted and wrong.
But when you don't know what a code does, just run it "manually"
int main(int argc, char **argv) {
int i;
for(i = fork(); i < fork(); i++)
execlp(“echo”, “sono”, argv[0], 0);
system(“echo i+$i”);
}
parent process:
i = fork();
here i contains the PID of the newly created process
execlp(“echo”, “sono”, argv[0], 0);
as #Whozcraig corrected me in the comment (and shame on me for making that 1st year mistake)
it runs echo and outputs "sono a.out" on the output (considering the name of prog is a.out). execlp() replaces the current process with its arguments and stops execution here.
before edit I was saying it was fork()ing indefinitely
child process:
i = fork();
here i contains the value 0, indicating this is the newly created process.
execlp(“echo”, “sono”, argv[0], 0);
is out again… replacing current process with its arguments and stops execution once echo is over.
*before edit, I was saying it was fork()ing again.
So at first look it looks like you got a twisted and crazy fork bomb, that will grow exponentially. But in the end, you got a twisted and crazy single fork that only executes the execlp() content twice.
N.B.: system(“echo i+$i”); is nonsense, as $i has no meaning in the context of this code. Even though it will never be executed.
in the end your instructor is really perverse.

What is the difference between fork()!=0 and !fork() in process creation

Currently, I am doing some exercises on operating system based on UNIX. I have used the fork() system call to create a child process and the code snippet is as follows :
if(!fork())
{
printf("I am parent process.\n");
}
else
printf("I am child process.\n");
And this program first executes the child process and then parent process.
But, when I replace if(!fork()) by if(fork()!=0) then the parent block and then child block executes.Here my question is - does the result should be the same in both cases or there is some reason behind this? Thanks in advance!!
There is no guaranteed order of execution.
However, if(!fork()) and if(fork()!=0) do give opposite results logically: if fork() returns zero, then !fork() is true whilst fork()!=0 is false.
Also, from the man page for fork():
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.
So the correct check is
pid_t pid = fork();
if(pid == -1) {
// ERROR in PARENT
} else if(pid == 0) {
// CHILD process
} else {
// PARENT process, and the child has ID pid
}
EDIT: As Wyzard says, you should definitely make sure you make use of pid later as well. (Also, fixed the type to be pid_t instead of int.)
You shouldn't really use either of those, because when the child finishes, it'll remain as a zombie until the parent finishes too. You should either capture the child's pid in a variable and use it to retrieve the child's exit status:
pid_t child_pid = fork();
if (child_pid == -1)
{
// Fork failed, check errno
}
else if (child_pid)
{
// Do parent stuff...
int status;
waitpid(child_pid, &status, 0);
}
else
{
// Child stuff
}
or you should use the "double-fork trick" to dissociate the child from the parent, so that the child won't remain as a zombie waiting for the parent to retrieve its exit status.
Also, you can't rely on the child executing before the parent after a fork. You have two processes, running concurrently, with no guarantee about relative order of execution. They may take turns, or they may run simultaneously on different CPU cores.
The order in which the parent and child get to their respective printf() statements is undefined. It is likely that if you were to repeat your tests a large number of times, the results would be similar for both, in that for either version there would be times that the parent prints first and times the parent prints last.
!fork() and fork() == 0 both behave in the same way.
The condition itself cannot be the reason the execution sequence is any different.
The process is replicated, which means that child is now competing with parent for resources, including CPU. It is the OS scheduler that decides which process will get the CPU.
The sequence in which child and parent processes are being execute is determined by the scheduler. It determines when and for how long each process is being executed by the processor. So the sequence of the output may vary for one and the same program code. It is purely coincidental that the change in the source code led to the change of the output sequence.
By the way, your printf's should be just the other way round: if fork() returns 0, it's the child, not the parent process.
See code example at http://en.wikipedia.org/wiki/Fork_%28operating_system%29. The German version of this article (http://de.wikipedia.org/wiki/Fork_%28Unix%29) contains a sample output and a short discusion about operation sequence.

fork: where does the child start running?

Is the child, after the fork, start the program from the beginning or from the place of is parent?
for example, it this program, is the child start from line 1 or line 3?
int i=1
fork()
i=i*2
fork
i=i*2
fork() creates a new process by duplicating the calling process.
The new process, referred to as the child, is an exact duplicate of
the calling process, referred to as the parent, except for the
following points: […]
from fork(2)
As it is an exact duplicate, it will also have the same instruction pointer and stack. So the child will be right after the call to fork(). Now, you may ask, how do I find out whether the current program is the child or the parent? See the manpage on the 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.
So if the result of fork() is equal to 0, you're in the child process, if its greater than 0 you're in the parent and if its below 0 you're in trouble.
Please note that this implies that every code which is independent of the result value of fork(), will be executed in both the child and the parent. So if you're for example creating a pool with 16 processes, you should be doing:
for (int i = 0; i < 16; i++) {
pid_t pid = fork()
if (pid == 0) {
do_some_work();
exit(0);
} else if (pid < 0) {
// fork failed
do_some_error_handling();
}
}
If you miss the exit(0), you'll spawn 2¹⁶-1 processes (been there, just with 100 instead of 16. No fun.)
The fork starts from line 3, the point where the fork occurred.
When fork returns, it returns in both the parent (returning the PID of the child) and the child (returning 0). Execution continues from there in both the parent and the child.
As such, typical use of fork is something like:
if (0 == (child = fork()))
// continue as child.
else
// Continue as parent.
The Child will be created at line 2 i.e., fork() but it will start its execution from the line 3 i.e., i = i*2. What confuses me here is your line 4. What are you trying to do there?

Resources