Fork() to performe different processes - c

I'm trying to use the multiple fork() calls to create several children with different task
I found a code on
Multiple child process
Which is really close for what I want , yet I couldn't fully understand it
pid_t firstChild, secondChild;
firstChild = fork();
if(firstChild != 0)
{
// In parent
secondChild = fork();
if(secondChild != 0)
{
// In parent
}
else
{
// In secondChild
}
}
else
{
// In firstChild
}
My questions are:
How many process have been created (I assume that we have 4 since it's 2 forks!)?
In this part of the code
firstChild = fork();
if(firstChild != 0)
{
// In parent
secondChild = fork();
if(secondChild != 0)
{
// In parent
}
Does "//in parent" mean both of them are the same process (they have the same PID when I tried to test it).
How can I create 3 children using 2 forks?( I can draw the tree that ends with 4 leaves 3 of them are children and 1 parent)
Thank you (please feel free to tell me if I'm not totally getting the Fork concept)

How many process have been created (I assume that we have 4 since it's 2 forks!)?
Depending on the result of your forks it should be 0 to 2. Probably 2 if nothing goes wrong. There's a parent process that forks 2 children processes.
Does "//in parent" mean both of them are the same process (they have the same PID when I tried to test it).
Yes. In your case the code is checking for a return value of fork being non zero. That's not a very good idea since it covers 2 distinct cases:
It could be less than zero indicating an error, or ...
It could be greater than zero indicating to the parent the pid of the newly spawned process
Anyway ... considering all goes well and both the forks succeed, you will end up with a parent process having 2 different children.
How can I create 3 children using 2 forks?( I can draw the tree that ends with 4 leaves 3 of them are children and 1 parent
Something like this should do the trick:
firstChild = fork();
if (firstChild < 0) {
exit(EXIT_FAILURE);
perror("fork");
}
secondChild = fork();
Notice that by not checking the return value of fork() any more I'm getting a child process continuing execution at the same place as the parent. So the next fork will actually be executed by both the parent and the children each spawning a new process. So I'll get something like this ...
parent─┬─child1───(child1's child)
└─child2
I can't think of any way you can get this with only 2 forks though:
parent─┬─child1
├─child3
└─child2
Note: It's customary on stackoverflow to only limit yourself to one question per topic.

The following code shows how to create 4 process (1 parent 3 children) with only 2 forks
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int *list;
void calculate_average(int );
void calculate_maximum(int);
void calculate_minimum(int);
void calculate_average(int count)
{
int i, total = 0;
for (i = 0; i < count; i++)
total += list[i];
double average = total / count;
printf("average is %f\n",average);
}
void calculate_maximum(int count)
{
int i;
int maximum = list[0];
for (i = 1; i < count; i++)
if (list[i] > maximum)
maximum = list[i];
printf("maximum is %d\n",maximum);
}
void calculate_minimum(int count)
{
int i;
int minimum = list[0];
for (i = 1; i < count; i++)
if (list[i] < minimum)
minimum = list[i];
printf("minimum is %d\n",minimum);
}
int main(int argc, char *argv[])
{
pid_t pid, pid1;
int num_of_args = argc-1;
int i;
/* allocate memory to hold array of integers */
list = malloc(sizeof(int)*num_of_args);
for (i = 0; i < num_of_args; i++)
list[i] = atoi(argv[i+1]);
printf("The %d number of input ingeters are\n",num_of_args);
for (i = 0; i < num_of_args; i++)
printf("%d\n",list[i]);
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* P2 */
pid1=getppid();
calculate_average(num_of_args);
}
else { /* P1 */
pid1=getpid();
wait(NULL);
}
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed\n");
return 1;
}
else if (pid == 0) { /* could be either P3 or P4 */
if (getppid() == pid1) { /* P3 */
calculate_minimum(num_of_args);
}
else { /* P4 */
calculate_maximum(num_of_args);
}
}
else {
wait(NULL);
}
return 0;
}
Note that one of the children will be a parent for a grandchild

Related

Count the number of process created by fork() [duplicate]

How can I display the number of processes created?
(without using a formula)
for (i=0; i<3; i++)
fork();
count = count + 1;
printf("%d",count);
There are a number of ways to do this, and a good technique is to have each child write one byte into a file descriptor which the original process can read. Note that, for the sake of brevity, the following code contains absolutely no error checking. Also, we report only the number of spawned processes (7) rather than counting the original to get a count of 8:
int main(void) {
int fd[2];
int depth = 0; /* keep track of number of generations from original */
int i;
pipe(fd); /* create a pipe which will be inherited by all children */
for(i=0; i<3; i++) {
if(fork() == 0) { /* fork returns 0 in the child */
write(fd[1], &i, 1); /* write one byte into the pipe */
depth += 1;
}
}
close(fd[1]); /* exercise for the reader to learn why this is needed */
if( depth == 0 ) { /* original process */
i=0;
while(read(fd[0],&depth,1) != 0)
i += 1;
printf( "%d total processes spawned", i);
}
return 0;
}
Printing the count value out just once is the easy part. Because you can get the process pid before the for loop. And then get the pid again after the for loop and only print if the pids match. For the counting part, it depends on whether your child processes exit or not. If they exit the solution is easier. The below code demonstrates one possible solution if the child processes exit (for brevity have not done full error checking). The idea is that each child process counts its own children. Parent waits for each child to complete and adds in its count. Haven't had time to fully test/debug the program so there may be some errors. But hopefully gives you the general idea.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t before_pid, after_pid;
pid_t forked_pid;
int count;
int i;
int status;
before_pid = getpid();
count = 1; /* count self */
for (i = 0; i < 3; i++) {
forked_pid = fork();
if (forked_pid > 0) {
waitpid(forked_pid, &status, 0);
/* parent process - count child and descendents */
count += WEXITSTATUS(status);
} else {
/* Child process - init with self count */
count = 1;
}
}
after_pid = getpid();
if (after_pid == before_pid) {
printf("%d processes created\n", count);
}
return (count);
}

Get pid from brother process

I want to have a parent process and three child processes. I want these child processes to know the pids of the other child processes.
The problem is that when I do fork and then I do it again, the second fork is also executed in the child process creating an extra process (or so I think).
How could I solve it?
Thanks.
The parent should fork three times, the children should not fork. This way, the parent will know the pids of all three children.
After the fork, you'll need some kind of separate communication channel by which the parent can communicate these pids to all children. A simple way would be to open a pipe (see pipe(2)) before forking each child, so the child inherits the pipe's file descriptor (at least the read end) and the parent keeps the write end. Then have the parent send the three pids down each pipe and close it.
Example code (long, but that's the nature of C):
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 3
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}
As #PSkocik points out in their answer, you should probably not be doing this. Pids can be reused by the OS, so there's no way for the children to know that their sibling pids still actually refer to their siblings; only the parent can be sure, because it has to wait for each pid before it can be reused.
However, this same mechanism can be used for other forms of IPC (inter-process communication); you could, for example, use it to create pipes between the children directly.
You can use shared memory or some other kind of IPC to communicate the PIDs, but you probably shouldn't even try.
PIDs are subject to recycling and you can only ever know for sure if a PID refers to the process you think it refers to if that PID belongs to a child process of yours (because then you can know if you've waited on it or not).
Otherwise, PIDs (of non-children) are racy references which are basically only usable for hacky debugging.

Creating process tree using fork

I'm trying to create the process tree shown in the picture. Basically if the level is even I want to create one child process and terminate the parent process. If the level is odd I wanna create two child processes and then terminate the parent process. I have written a program right now but I think it's so hard to visualize what process tree my program is actually creating. I've written some comments to the code to explain how I've been thinking. I also want to output the PID of the bottom children of the tree which my code doesn't do correctly.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]){
pid_t pid, ppid;
int n, i;
int childstate;
int count = 0;
if(argc != 2){
printf("Wrong number of arguments");
exit(-1);
}
n = atoi(argv[1]);
fork(); //start process 0
for(i = 1; i < n + 1; i++){
if(i % 2 != 0){
fork(); //if odd level start 1 child process
if(getpid() == 0){
kill (getppid(), 9); //terminate parent process
}
} else {
if(fork() > 0){ //start new process
fork(); //if new process is not a child start another process
if(getpid() == 0){
kill (getppid(), 9); //terminate parent process
}
}
}
if(i == n){ //print pid of leaves (not working correctly)
printf("Process: %d \n", getpid());
}
}
return 0;
}
I also want to output the PID of the bottom children of the tree which my code doesn't do correctly.
Have your processes output the tree in Dot language, and use Graphviz to output the tree.
For example, if you save the following as say tree.c:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int process(const unsigned int level, const unsigned int maxlevel, FILE *dot)
{
int status = EXIT_SUCCESS, childstatus;
unsigned int children, i;
pid_t p, child[2];
if (dot) {
/* Output a node for this child, */
fprintf(dot, " \"%ld\" [ label=\"Process %ld\" ];\n", (long)getpid(), (long)getpid());
/* and if not at the top level (0), an edge from our parent. */
if (level)
fprintf(dot, " \"%ld\" -> \"%ld\";\n", (long)getppid(), (long)getpid());
fflush(dot);
}
/* No more forking? */
if (level >= maxlevel) {
if (level)
exit(status);
else
return status;
}
/* Odd levels create two child processes, even one. */
if (level & 1)
children = 2;
else
children = 1;
/* Fork the child processes, */
for (i = 0; i < children; i++) {
child[i] = fork();
if (child[i] == -1) {
fprintf(stderr, "Cannot fork: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
} else
if (!child[i]) {
/* have each child run process() and nothing else, */
exit(process(level + 1, maxlevel, dot));
}
/* This line is run in parent only. */
}
/* and wait for them. */
for (i = 0; i < children; i++) {
if (child[i] != -1) {
do {
p = waitpid(child[i], &childstatus, 0);
} while (p == -1 && errno == EINTR);
if (p != child[i])
status = EXIT_FAILURE;
} else
status = EXIT_FAILURE;
}
if (level)
exit(status);
else
return status;
}
int dot_process_tree(const int levels, FILE *out)
{
int retval = EXIT_SUCCESS;
if (out) {
fprintf(out, "digraph {\n");
fflush(out);
}
if (levels > 0)
retval = process(0, levels - 1, out);
if (out) {
fprintf(out, "}\n");
fflush(out);
}
return retval;
}
int main(void)
{
return dot_process_tree(5, stdout);
}
and compile and run it using
reset ; gcc -Wall -Wextra -O2 tree.c -o tree && ./tree | dot -Tx11
you'll get a nice graphic process tree. (Use dot -Tsvg > out.svg or dot -Tpng > out.png to save it as an SVG or PNG image.) On my system:
Do note that there is no reason why the process IDs should be in the tree order. Although e.g. Linux hands them off in a rather ordered fashion, they can be in any order, even totally random. So do not make any assumptions on the PIDs.
The Dot language itself is simple. The output of the above program is something like
digraph {
"12375" [ label="Process 12375" ];
"12377" [ label="Process 12377" ];
"12375" -> "12377";
"12378" [ label="Process 12378" ];
"12377" -> "12378";
"12379" [ label="Process 12379" ];
"12377" -> "12379";
"12380" [ label="Process 12380" ];
"12378" -> "12380";
"12381" [ label="Process 12381" ];
"12379" -> "12381";
"12382" [ label="Process 12382" ];
"12380" -> "12382";
"12384" [ label="Process 12384" ];
"12381" -> "12384";
"12383" [ label="Process 12383" ];
"12380" -> "12383";
"12385" [ label="Process 12385" ];
"12381" -> "12385";
}
which should be obvious; nodes are named by the process ID, and [ label="Title" ] sets the text in the node. It is not from the same run as the diagram above, so the process IDs differ.
In Dot, numbers do need to be quoted if used as a name, but if a name starts with a letter, you don't need to quote it. See Graphviz documentation for further details. (The Node, Edge and Graph Attributes page is the one you usually need.)
If you want the level display in each node, use
fprintf(dot, " \"%ld\" [ label=\"Process %ld, level %u\" ];\n", (long)getpid(), (long)getpid(), level + 1);
in process(). (It uses level 0 forwards, with all nonzero levels being child processes, and level 0 being the original process. That's why level 0 returns, and all other levels exit().)
From you description, your basic logic should be:
void fork_loop(int level, int stop) {
if (level > stop) return;
if (is_even(level)) {
fork_child(level, stop);
exit(0);
} else {
fork_child(level, stop);
fork_child(level, stop);
exit(0);
}
}
Where fork_child() calls fork(). The child process would call fork_loop(level+1, stop), while the parent would return.
fork(); //if odd level start 1 child process
if (getpid() == 0){
kill (getppid(), 9); //terminate parent process
}
This logic is wrong: getpid() does not return 0 / fork doesn't return a pid in the child process - it just returns 0 to signify that it is the child process - it can know parent's pid by calling getpid before.
The logic should be:
pid_t child = fork();
if (child > 0) {
// use exit instead of kill! exit terminates this process
exit(0);
}
if (child < 0) {
... an error occurred in fork ...
}
The getpid can never be zero. As I mentioned in my top comments, you want the parent to wait on children, not the other way round and too many forks.
Here's a cleaned up version that I think works:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
pid_t pid;
pid_t ppid;
int i;
int n;
int pcur;
int pcnt;
if (argc != 2) {
printf("Wrong number of arguments");
exit(-1);
}
n = atoi(argv[1]);
pid = fork(); // start process 0
if (pid != 0) {
wait(NULL);
n = -5;
}
for (i = 1; i < n + 1; i++) {
// odd/even level -- get number of children to start
// NOTE: you may need to reverse this if
if (i % 2 != 0)
pcnt = 1;
else
pcnt = 2;
// get parent pid
ppid = getpid();
// do the forks
for (pcur = 0; pcur < pcnt; ++pcur)
fork();
// get current pid
pid = getpid();
// parent should wait on children
if (pid == ppid) {
while (wait(NULL) >= 0);
break;
}
// print pid of leaves (not working correctly)
if (i == n) {
printf("Process: %d\n", pid);
}
}
return 0;
}

C - Forking from a single parent

I'm trying to write a small program that forks processes from a single parent. Currently my code does this a few times but then the children create more child processes, which I want to eliminate.
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c > 0 ) {
printf("parentID = %d, childID = %d\n", getppid(i), getpid(i));
}
}
}
I'm not sure how to modify it so that fork is only forking from the parent though.
EDIT: thanks for the help, got the solution:
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c > 0 ) {
printf("parentID = %d, childID = %d\n", getppid(i), getpid(i));
}
else {
exit(0);
}
}
}
nothing in the posted code is recognizing the child (0 == pid)
so a child hits (and skips) the two 'if' statements.
hits the end of the loop,
branches back to the top of the loop, calls fork()....etc.
Suggest: adding
elseif( 0 == pid )
{ // then child ...
exit( EXIT_SUCCESS );
}
The child process does not enter any part of the if block, and just loops back to the top of the for loop creating more children. Also, the if (n > 0) block gets run for the parent, not the child, since fork returns 0 to the parent and the child's pid to the parent.
Change if (n > 0) to if (n == 0), and call exit() at the bottom of the block to prevent the child from continuing. Also, getpid() and getppid() don't take any arguments.
int main() {
pid_t c;
for (int i = 0; i < 5; i++) {
c = fork();
if(c < 0) {
perror("fork");
exit(1);
}
else if( c == 0 ) {
printf("parentID = %d, childID = %d\n", getppid(), getpid());
exit(0); // <-- here
}
}
}

Display number of processes in loop with fork

How can I display the number of processes created?
(without using a formula)
for (i=0; i<3; i++)
fork();
count = count + 1;
printf("%d",count);
There are a number of ways to do this, and a good technique is to have each child write one byte into a file descriptor which the original process can read. Note that, for the sake of brevity, the following code contains absolutely no error checking. Also, we report only the number of spawned processes (7) rather than counting the original to get a count of 8:
int main(void) {
int fd[2];
int depth = 0; /* keep track of number of generations from original */
int i;
pipe(fd); /* create a pipe which will be inherited by all children */
for(i=0; i<3; i++) {
if(fork() == 0) { /* fork returns 0 in the child */
write(fd[1], &i, 1); /* write one byte into the pipe */
depth += 1;
}
}
close(fd[1]); /* exercise for the reader to learn why this is needed */
if( depth == 0 ) { /* original process */
i=0;
while(read(fd[0],&depth,1) != 0)
i += 1;
printf( "%d total processes spawned", i);
}
return 0;
}
Printing the count value out just once is the easy part. Because you can get the process pid before the for loop. And then get the pid again after the for loop and only print if the pids match. For the counting part, it depends on whether your child processes exit or not. If they exit the solution is easier. The below code demonstrates one possible solution if the child processes exit (for brevity have not done full error checking). The idea is that each child process counts its own children. Parent waits for each child to complete and adds in its count. Haven't had time to fully test/debug the program so there may be some errors. But hopefully gives you the general idea.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t before_pid, after_pid;
pid_t forked_pid;
int count;
int i;
int status;
before_pid = getpid();
count = 1; /* count self */
for (i = 0; i < 3; i++) {
forked_pid = fork();
if (forked_pid > 0) {
waitpid(forked_pid, &status, 0);
/* parent process - count child and descendents */
count += WEXITSTATUS(status);
} else {
/* Child process - init with self count */
count = 1;
}
}
after_pid = getpid();
if (after_pid == before_pid) {
printf("%d processes created\n", count);
}
return (count);
}

Resources