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

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.

Related

The initial process creates 5 child processes, and waits for them to finish. Each child process performs 5 repetitions, where in each repetition

I'm a bit confused with the creation of processes with fork(), sleep() and wait() in c. Take the following piece of code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void childProcess(void);
void childProcess(void)
{
for(int i = 0; i < 5; i++)
{
printf("pid: %d email: myemail\n", getpid());
sleep(1);
}
}
int main(int argc, char *argv[])
{
for (int i = 0; i < 5; i++)
{
pid_t childpid;
if ((childpid = fork()) == 0)
{
childProcess();
exit(0);
}
}
int status;
while (wait(&status) > 0)
{
}
return 0;
}
After this piece of code has been executed,executes processes but does not remove repetitions from 5 processes. I'm a little confused with the process.
The initial process creates 5 child processes, and waits for them to finish.
Each child process performs 5 repetitions, where in each repetition:
Prints the message
pid: PID email: USER_EMAIL
where PID is the child PID of the process, while USER_EMAIL is the email
Suspends its operation for 1 second (at a time) with the sleep call
The parent process prints the children's PIDs when they are finished
P.S I EDIT THE CODE
#mixalispetros, you have multiple things to fix, and they all have to be fixed together for your code to work as intended.
exit(0);
for (int i = 0; i < 5; i++) {
wait(NULL);
}
The process ends on exit(0). wait is never called.
if (fork() == 0) {
// what code runs here? The code in the new process
}
What code runs within the fork() conditional? The new process's code. Which process should run wait()? The original process. So in addition to being after an exit, the wait() is also in the wrong process.
Where to move it? The for loop wait()s for 5 child processes. Why would there be 5 child processes for which to to wait()? Because we had already started all 5 child processes before we went into our loop of 5 wait()s.
The wait()s must happen not just outside the child process conditional block, but also outside the loop around the call to fork().
I'm a bit confused with the creation of processes with fork(), sleep() and wait() in c
It is confusing. Refer to the documentation often to keep it straight.
Remember, fork() returns twice - in the original process (returning the process ID of the new process), and in the new process (returning 0). wait(), will wait for the next child process to exit.
In summary, put the wait loop outside the loop that fork()s child processes. This will also move it ouside the block of code that executes in the child process.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main() {
// this loop creates 5 processes
for (int i = 0; i < 5; i++) {
if (fork() == 0) {
printf("Child %d, PID %d\n", i, getpid());
sleep(i);
exit(0);
}
}
// now, all subprocesses were started
// wait for the same number of child processes to end
for (int i = 0; i < 5; i++) {
wait(NULL);
}
}

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).

Program hangs after receiving proper result from child processes through pipe()

I'm splitting a file, sending through pipe(), having children find the sum of their designated section of the file, returning the calculated sum to the parent through pipe(), and having the parent calculate the sum of the child sums.
I've got a working program. My issues is that it hangs after receiving showing the proper final value.
I'm not sure what I'm doing to have the parent expect more information, but I'd bet it has something to do with my for() loop containing my child code.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int numchild;
int i, j, len, fpos=0, val, count=0, total=0, alltotal=0;
pid_t pid;
int nums = 1000;
FILE * file;
printf("How many children to use: ");
scanf("%d", &numchild);
printf("\nWill use %d child process(es).\n", numchild);
int fd[2*numchild][2]; //parent+child pipe
// create all pipes
for (i=0; i<2*numchild; i++)
{
pipe(fd[i]);
}
for (i=0; i<numchild; i++)
{
if((pid = fork()) == 0) // child process
{
pid = getpid();
// read from parent
len = read(fd[i][0], &fpos, sizeof(fpos));
if (len > 0)
{
file = fopen("file1.dat", "r");
fseek (file, fpos, SEEK_SET);
count = 0;
total = 0;
printf("Child(%d): Recieved position: %d\n", pid, fpos);
// read from file starting at fpos
// add values read to a total value
while (count < (nums/numchild))
{
fscanf(file, "%i", &val);
total += val;
count++;
}
//write to parent
write(fd[i+numchild][1], &total, sizeof(total));
printf("Child(%d): Sent %d to parent.\n", pid, total);
}
else
{
printf("Child(%d): Error with len\n", pid);
}
_exit;
}
// parent process
pid = getpid();
fpos = ((i*nums*5)/numchild); // 5 is the offset of the file values
// write to child process
printf("Parent(%d): Sending file position to child\n", pid);
write(fd[i][1], &fpos, sizeof(fpos));
// wait for child responce
len = read(fd[i+numchild][0], &total, sizeof(total));
if (len > 0)
{
printf("Parent(%d): Recieved %d from child.\n", pid, total);
alltotal += total;
printf("Parent(%d): Total: %d\n", pid, alltotal);
}
else
{
printf("Parent(%d): Error with len\n", pid);
}
}
}
I can't ask more questions, but if this is on Linux or Unix like systems (perhaps all posix):
You must do a wait (man 2 wait) for each of your child processes in your main program or you will create zombie processes.
Not knowing what environment you are running in makes it impossible for me to test this to determine if that is the cause of your not exiting properly.
Also (this is more like a comment), each cycle through the loop you are forking one child, then feeding it data, then getting a response, then printing the total. Is that really what you want to do? You don't need to create a bunch of pipes if you are only running one child at a time.
My guess is that you want to have some actual concurrency. You can do this by having a loop that creates all of the children followed by another loop that feeds them data, followed by a third loop that looks at the results and sums them, followed by a fourth loop that waits for each to terminate (to avoid zombies).
I would consider using poll or select to read the returns -- after all, there is no guarantee that the children will finish in order.
I won't select this as an answer until other people let me know this is probably what fixed it, but I believe that my program was hanging because the main() function wasn't actually returning anything. When I went to put in time collection (save begin time, end time, calculate difference, output) it had to be done outside of my for loop, so it was the last statement right inside my main() method. This seems to have stopped the hanging.
Right after calling fork() in your if-statement, you need to call wait(). This makes causes your parent to wait for your child to exit, and then continue he execution when the child exits.

Using pipe(): How do I allow multiple child processes to execute simultaneously

I'm using pipe() to split up a file by index, send that index to child processes, have the child process calculate the sum of the numbers in its designated block of the file, and return its sum to the parent.
My children seem to execute in order, where I would like them to execute at the same time to make this process more efficient.
Here's the code I'm working with:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/select.h>
#include <time.h>
int main(int argc, char *argv[])
{
int numchild;
struct timeval stop, start;
int i, j, len, ret, fpos=0, val, count=0, total=0, alltotal=0;
pid_t pid;
int nums = 1000;
FILE * file;
printf("How many children to use: ");
scanf("%d", &numchild);
printf("\nWill use %d child process(es).\n", numchild);
gettimeofday(&start, NULL);
int fd[numchild][2]; //parent to child. one for each
int results[2]; //all children to parent
pipe(results);
fd_set result_fd;
FD_ZERO(&result_fd);
FD_SET(results[0], &result_fd);
struct timeval tm = {.tv_sec=0, .tv_usec=1};
// create all pipes
for (i=0; i<numchild; i++)
{
pipe(fd[i]);
}
for (i=0; i<numchild; i++)
{
if((pid = fork()) == 0) // child process
{
pid = getpid();
// read from parent
len = read(fd[i][0], &fpos, sizeof(fpos));
if (len > 0)
{
file = fopen("file1.dat", "r");
fseek (file, fpos, SEEK_SET);
count = 0;
total = 0;
printf("Child(%d): Recieved position: %d\n", pid, fpos);
// read from file starting at fpos
// add values read to a total value
while (count < (nums/numchild))
{
fscanf(file, "%i", &val);
total += val;
count++;
}
//write to parent
write(results[1], &total, sizeof(total));
printf("Child(%d): Sent %d to parent.\n", pid, total);
}
else
{
printf("Child(%d): Error with len\n", pid);
}
_exit(0);
}
// parent process
pid = getpid();
fpos = ((i*nums*5)/numchild); // 5 is the offset of the file values
// write to child process
printf("Parent(%d): Sending file position to child\n", pid);
write(fd[i][1], &fpos, sizeof(fpos));
// wait for child responce
ret = select(FD_SETSIZE+1, &result_fd, NULL, NULL, NULL); //&tm
if (FD_ISSET(results[0], &result_fd))
{
ret = read(results[0], &total, sizeof(total));
// output total
printf("Parent(%d): Recieved %d from child.\n", pid, total);
alltotal += total;
//printf("\tParent(%d): Total: %d\n", pid, alltotal);
}
}
wait(0);
gettimeofday(&stop, NULL);
printf("\tTime elapsed: %lu microseconds\n", stop.tv_usec - start.tv_usec);
printf("\tParent(%d): Total: %d\n", pid, alltotal);
}
Please let me know what I need to change to have the child processes run simultaneously (not wait to run at the exact same time, but run as soon as the parent gives them their index, instead of waiting for the previous child to complete).
From the comments above, I conclude that:
1. this is an assignment of some type
2. it requires using fork and pipe
If I were doing something like this for real (and it's not clear that it would be worth doing), I would probably be using threads queues and semaphores.
Given the constraints, I'll try to answer your question.
The problem is that you are have the parent code inside the for loop. So what is happening is that each time through the loop, the parent is spawning a child, then sending the offset information, then waiting for the result. So that forces the child to complete before the parent goes through the next iteration of the loop.
The answer is to have more than one loop. In the first loop, spawn all of the children. In the second loop, send the children their offsets. In the third loop, collect the results. In the fourth loop wait for the children to terminate. It would probably be faster if you sent the children their offsets in the first loop.
Another way to do this is to set the offset in a variable prior to doing each fork. That would obviate the need to use pipes for the input. I believe that you could also have each child just exit with the sum. Then the return exit status of the child could be the sum. The parent could just total the sums and you avoid using a return pipe. That would be a better way to do this -- though it wouldn't follow your apparent rules.

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