fork() example program. need explanation - c

this is my code. Please have a look. Can you explain the process flow? it is actually a past paper question. But, I frankly don't understand the concept of fork system calls.
main()
{
int i = 1;
int ret_val= 0;
while(i <= 5)
{
fork();
if(ret_val == 0) /*child code*/
{
printf("in child %d. \n", i);
exit(0);
}
else
{ /*parent code*/
i = i+1;
}
}
}

First of all, in the core image of your program, you initialise two values, ret_val, and i which acts as a counter.
From there on, for 5 times, you fork() the program, creating another process with the same image (code). At this point I am assuming your code is wrong, because you are using the ret_val variable to check if it's the child or parent process, but to do so, you need to assign it the value from fork() like this:
ret_val = fork();
if (ret_val == 0)
// do something as child
else
// parent code here
In essence, your code, for 5 times, increments the value of i and has each child process display the current value of i.

Related

Fork() code not working as expected - Hierarchy making

Good afternoon.
I am currently working on a C program that takes one and only one parameter which designates the number of "child generation"s to be created (the own father counts as 1 already). "wait()" system calls are not to be used for this exercise (the version with "wait" calls happens to work exactly as expected).
For instance, the call $program 4 should generate a hierarchy like this:
Process A creates B
Process B creates C
Process C creates D
The printed messages are not important, as they are merely orientative for the task. With the following code (which happens to work exactly how I want with a "wait()" call) states that all the child processes derive from the same father, which I don't understand why it's happening.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int counter; pid_t result; int i;
/*
We are going to create as many processes as indicated in argv[1] taking into account that the main father already counts as 1!
*/
if (argc > 2 || argc == 1) {puts("IMPOSSIBLE EXECUTION\n"); exit(-1);}
int lim = atoi(argv[1]);
//We eliminate the impossible cases
if (lim < 1) {puts("IMPOSSIBLE EXECUTION\n"); exit(-1);}
if (lim == 1) {puts("The father himself constitutes a process all by his own, therefore:\n");
printf("Process%d, I'm %d and my father: %d\n", counter, getpid(), getppid());
}
else {
for (i = 0; i < lim; i++) {
result = fork();
if (result < 0) {
printf("Call%d \n", counter); perror("Has failed!");
exit(-1);
}
else if (result) {
break; //Father process
}
else {
counter++; //Child processes increment the counter
printf("Process%d, I am %d and my father: %d\n", counter, getpid(), getppid());
}
}
}
The hierarchy generated by the code above is not the one I expected...
All help is greatly appreciated.
Thank you
With the following code (which happens to work exactly how I want with
a "wait()" call) states that all the child processes derive from the
same father, which I don't understand why it's happening.
I don't see that in my tests, nor do I have any reason to expect that it's actually the case for you. HOWEVER, it might appear to be the case for you if what you see is some or all of the child processes reporting process 1 as their parent. That would happen if their original parent terminates before the child's getppid() call is handled. Processes that are orphaned in that way inherit process 1 as their parent. If the parent wait()s for the child to terminate first then that cannot happen, but if instead the parent terminates very soon after forking the child then that result is entirely plausible.
Here's a variation on your loop that will report the original parent process ID in every case:
pid_t my_pid = getpid();
for (i = 0; i < lim; i++) {
result = fork();
if (result < 0) {
printf("Call%d \n", counter); perror("Has failed!");
exit(-1);
} else if (result) {
break; //Father process
} else {
pid_t ppid = my_pid; // inherited from the parent
my_pid = getpid();
counter++; //Child processes increment the counter
printf("Process%d, I am %d and my father: %d\n", counter, (int) my_pid, (int) ppid);
}
}
You are missing a crucial function call.
for (i = 0; i < lim; i++) {
fflush(stdout); // <============== here
result = fork();
Without it, your fork duplicates parent's stdout buffer into the child process. This is why you are seeing parent process output repeated several times --- its children and grandchildren inherit the output buffer.
Live demo (with fixed formatting for your reading convenience).

C: why after fork() child block is not running?

I'm studying how fork() actually works so my code below has no purpose other than spawning new processes with fork() and see them die randomly. So:
I put my fork() in a for loop (to run twice for now) to see more than one child be created, and to my surprised it seems that the second Child has a parent that was not the same parent as the first child. So, if my initial PID was 1000, the two child created would be 1002 (child of 1000) and 1003 (child of 1001???). I didn't understand what happened that a parent was created. This guy explained but I can't say I fully understood.
To try and find out what was going on, I printed my parent (and child) processes with their PID, but if I declare a char for my parent, my child won't run the function. I explain what I mean in my code between <<< >>>.
So, can anyone help me understand my 1st point, and identify why 2 is happening?
Full code below:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
const int PASS = 5;
const int RANDLIMIT = 5;
const int FORKNUMBER = 2;
int i = 0;
void doSomeWork(char *who);
int main(int argc, char *argv[])
{
printf("Just started, I am: %d\n", (int) getpid());
int j;
pid_t pid;
for (j=0; j < FORKNUMBER; j++)
pid = fork();
printf("fork returned: %d\n", (int) pid);
srand((int) pid + rand());
if (pid < 0) {
perror("fork failed");
} else if (pid == 0) {
char * childPid;
char * childName;
sprintf(childPid, "%d", (int) getpid());
childName = (char *) malloc(strlen("Child - ") + strlen(childPid) + 1 );
strcpy(childName, "Child - ");
strcat(childName, childPid);
doSomeWork(childName);
exit(0);
}
//<<< The malloc above for the child to send a parameter >>>
//<<< to the function, works fine. But when I try to do >>>
//<<< the same for my parent, the simple declaration of a>>>
//<<< char below, makes the child block (the if PID==0) >>>
//<<< not run. The 3 lines commented below were an >>>
//<<< attempt to understand what was preventing the child>>>
//<<< block from running. Now, if the parent calls the >>>
//<<< function with a string not declared before, the >>>
//<<< child block runs fine.>>>
//char parentName[strlen("Parent") + 1];
//strcpy(parentName, "Parent");
//doSomeWork(parentName);
doSomeWork("Parent");
//wait(NULL);
return(0);
}
void doSomeWork(char *who)
{
int control = 0;
for(; i < PASS; i++){
sleep(rand() % RANDLIMIT);
printf("%s: Done pass #%d, my parent = %d\n", who, i, getppid());
if (control == 0)
{
char childWord[6];
strncpy(childWord, who, 5);
if (strcmp(childWord, "Child") == 0 && (int) getppid() == 1 )
{
control = 1;
printf("%s: became orphan at #%d\n", who, i);
}
}
}
printf("%s: exiting...\n", who);
}
EDIT:
For 1, I created a function like below:
int nbDigits(int number)
{
int i=0;
for(; number > 10; i++)
{
number /= 10;
}
return ++i;
}
Now instead of declaring a pointer to a char like this, char * childPid; I declared a char array like this char childPid[nbDigits(getpid()) + 1]; and everything worked like a charm.
Check out Joseph's suggestion below using asprintf(), seems neat.
You can't call fork() in a loop but only check what it returns at the end of the loop if you want your program to work. When you do so, you're starting an exponential number of child processes, and each one thinks it's "the parent" as long as it was the parent of its final fork(). Move your test of pid to inside the loop.
char * childPid;
sprintf(childPid, /* ... */);
That's going to clobber some random memory. You need to point childPid to something before you sprintf to it, or replace sprintf with something like asprintf that will allocate itself.
As soon as you run fork() any child process will start its execution from there.
Fork system call use for creates a new process, which is called child
process, which runs concurrently with process (which process called
system call fork) and this process is called parent process. After a
new child process created, both processes will execute the next
instruction following the fork() system call. source
Thus, when your first iteration happens (i=0) there will be a new process, with a new pid, and then, both parent and this child process will call the next iteration (i=1) and create a new child for each one with two more new pid. In the end, you will have 4 different pid.
Example
Parent process pid=1000
i = 0, creates pid=1001, now you have both 1000 and 1001
i = 1, creates a child from 1001 -> 1002 and a child from 1000 again, 1003.
In the end you have 1000, 1001, 1002 and 1003 and all of these four processes will run the following instruction which is the printf.

Theory,Processes fork()

Goodmorning, i would like to ask 2 things..
1) what returns a fork() did on a child which has already a pid==0 ? if i continue to fork on every son, each of them will have 0 as pid ?? or not ?
2) this is my file Buffer.c and it runs on a single process.
At the beginning it forks() out some Producers who produce() and some Consumers who consume() ,but I am afraid that every producers enters in the next for cicle and it starts to produce himself other consumers!! because it write pid=-1 so...
I want that this piece of code produce only P producers and C consumers, but i need to know why every producer do not create other consumers!
Can you help me,maybe giving me a scheme of how many processes i will create with this code?
Maybe doing a scheme as this:
Father:
8 producers
-
-
-
...
each of them produces: 5 consumers
etc etc......
int main(int argc, char **argv) {
/....
pid_t pid;
pid_t cons_pid[C];
/* fork producers */
pid = -1;
for(i=0; i<P && pid!=0; i++)
pid=fork();
switch(pid) {
case -1:
...
case 0:
/* GENERIC PRODUCER i */
...
/* PRODUCE() */
printf("Producer %d exits\n",i);
...
return 0;
}
/* fork consumers */
pid = -1;
for (j=0; j<C && pid!=0; j++)
pid = cons_pid[j] = fork();
switch(pid) {
case -1:
....error
case 0:
/* GENERIC CONSUMER j */
CONSUME()....
}
return 0;
}
what returns a fork() did on a child which has already a pid==0
0 is not a valid PID, hence by definition there can't be an process with PID=0 and thus PID=0 is a perfectly well defined return for indicating child status.
if i continue to fork on every son, each of them will have 0 as pid
No process ever has PID=0. All PIDs are greater than zero! A zero is just the return value received by the newly forked process to indicate that it's the child. The actual PID a child process got is queried using the getpid function from the child process. However the parent process can't perform such a query, since in the time between fork and a assumed query function call, the child may already have terminated (race condition). So you want fork to return the PID to the parent directly.
BTW: The terminology is parent and child not father and son (processes are things not people, despite what the TRON movies depict).
Regarding your code snippet: A switch statement is the wrong choice here. You want to use an if statement.
fork() splits up the current process into a father and a child. The child will have a new PID, the father retains the old PID. In both processes fork() returns after the splitting. In the father the return value will be the PID of the child (to make it known), and in the child the return value will be 0.
1) The lowest possible process ID is 1, this is the ID of the init process from which all other processes are forked. Therefore, it is not possible for a child or for your parent process to "already have ID 0". Your child's process ID is necessarily greater than 1. Thus, the problem that you are afraid of cannot happen.
2) The confusion that you state is the reason why fork (which returns twice, once for the parent and once for the newly created child!) has a somewhat "weird" return value which can have so many different values:
it can be -1, then something went wrong, and no child was created.
it can be a positive value, then you are in the parent process, and the value is the child's process ID. It's as if you called any other "normal" function that just returned normally.
it can be 0, then your code knows it is now running in the child process.
You must examine the return value (if()) so you know what process you are in. Then no such thing as you decribe can happen (or, should happen, this presumes your code does not have any bugs).
EDIT:
The code can be rewritten slightly so it gets rid of the && pid!=0 inside the loop and thus looks a bit less scary overall:
int main()
{
int pid, i;
pid_t cons_pid[C];
for(int i=0; i<P; ++i)
{
pid=fork();
if(pid == -1) exit(1); /* fork error */
if(pid == 0) { producer(); return 0; }
}
for(i=0; i<C; ++i)
{
pid = fork();
if(pid == -1) /* fork error */
{ /* should do a kill_producers(); here */ exit(2); }
else if(pid == 0) /* consumer */
{ consumer(); return 0; }
else /* master process, remember all consumer pids */
{ cons_pid[j] = pid; }
}
/* ... */
return 0;
}

Recursive Fibonacci using Fork in C (Pt 2)

I'm attempting to write a function that recursively computes the resulting fibonacci number from a given int n using forks in C.
Here is the function specification: If doPrint is true, print it. Otherwise, provide it to the parent process. The solution should be recursive and it must fork a new child for each call. Each process should call doFib() exactly once. The method signature cannot be changed. Helper functions cannot be used.
This is a continuation of this question: Recursive Fibonacci using Fork (in C)
Unfortunately, I never figured out a solution to the problem in the last post, however this is my modified code. I thought I had it figured out (psuedo code wise) but came to find out that I still am unsure about a few pieces.
At this point, this is solely for my amusement. This is not homework and won't be covered in my class again (after the most recent test, which has passed).
static pid_t root_pid;
// Function to return exit code for PID
static int exitcode(pid_t pid)
{
pid_t retpid;
int status;
retpid = waitpid(pid, &status, 0);
if (pid != retpid)
{
printf("waitpid error\n");
}
return WEXITSTATUS(status);
}
static void doFib(int n, int doPrint)
{
root_pid = getpid();
pid_t pid1;
int status1;
pid_t pid2;
int status2;
if(n < 2) // Base case, exit back to parent?
{
exit(n);
}
else // if not base case, fork child processes
{
pid1 = fork();
if (pid1 == 0) // Child Process 1 (for fib(n-1))
{
doFib(n-1, doPrint);
exit(n-1);
}
else if (pid1 > 0) // Parent Process
{
pid2 = fork();
if (pid2 == 0) // Child Process 2 (for fib(n-2))
{
doFib(n-2, doPrint);
exit(n-2);
}
// Get value from child process 1
status1 = exitcode(pid1);
// Get value from child process 2
status2 = exitcode(pid2);
// When to print?
if (getpid() == root_pid)
{
int result = status1 + status2;
if (doPrint)
{
printf("%d\n", result);
}
else
{
exit(result);
}
}
}
}
}
A few questions...
Do I need to call both of these functions for each child process?
doFib(n-1, doPrint); exit(n-1);
Is my base case at the beginning correct? (n < 2)
Is my base case at the end correct? (when to print)
Thank you for any help.
The answer for "when to print" really comes down to what you want to print ... if you only want to print the final answer, then you'll most likely need a flag that indicates when you're in the root parent process, and use the if statement to test if you are indeed the root parent so that you only print a single number. If on the other-hand you want to print the entire sequence up to the final number, then an if statement is not needed.
For instance, a good flag value would be the PID of the root process. You could save this in a global variable called root_pid in the first couple lines of main() before you start your forking off of separate child processes. That way all the child processes will have the same value set for root_pid, and the if statement can simply be if (getpid() == root_pid).
So do something like this:
//fib.c
#include <unistd.h>
pid_t root_pid
int main()
{
root_pid = getpid();
//... rest of your program
}
And as mentioned above, make your if statement inside of doFib the following:
if (getpid() == root_pid)
{
//...print results
}
else
{
exit(result)
}

How to run two child processes simultaneously in C?

So I'm getting into Concurrent Programming, but for some reason I can't even get the basics to work. I have a file called fork.c, which contains a method main. In this method main I fork twice, into child processes 1 and 2.
In child 1, I print the character 'A' 50 times.
In child 2, I print the character 'B' 50 times.
When I run my code, I get the output AAAAA...AAAABBBBBB....BBBBBB. But never something like ABABABABABABAB.... In fact, sometimes I even get BBBBB....BBBBAAAA....AAAAA.
So why am I experiencing this behavior? Perhaps I'm going about it completely wrong.
#include <stdlib.h>
#include <stdio.h>
void my_char(char n) {
write(1, &n, 1);
}
int main() {
int status;
pid_t child1, child2;
if (!(child1 = fork())) {
// first childi
int a;
for (a = 0; a < 50; a++) {
my_char('A');
}
exit(0);
} else if (!(child2 = fork())) {
// second child
int a;
for (a = 0; a < 50; a++) {
my_char('B');
}
exit(0);
} else {
// parent
wait(&child1);
wait(&child2);
my_char('\n');
}
return 0;
}
They are running concurrently, but the processes end almost immediately after being started. In other words, they're too short to actually get any real overlap.
EDIT:
The time needed to start another process is longer than the time it takes to run them. Therefore the chance of overlap is small. (there are also buffering issues which I'll omit)
You need each process to do more work than that. Try printing more than 50. Printing more than 10000 will probably be enough.
I think this is much easier to figure how fork() works:
#include <stdlib.h>
#include <stdio.h>
int main() {
pid_t child1, child2;
printf("Start\n");
if (!(child1 = fork())) {
// first childi
printf("\tChild 1\n");
sleep(5);
exit(0);
} else if (!(child2 = fork())) {
// second child
printf("\tChild 2\n");
sleep(5);
exit(0);
} else {
// parent
printf("Parent\n");
wait(&child1);
printf("got exit status from child 1\n");
wait(&child2);
printf("got exit status from child 2\n");
}
return 0;
}
...and here is the output:
Start
Child 1
Parent
Child 2
got exit status from child 1
got exit status from child 1

Resources