How Can I use fork() recursively? - c

I've been programming this over and over again and I've had trouble learning how to work with fork() in order to generate child processes recursively. I started programming some pretty complicated stuff and I decided to start over again with something way more simple.
I just started learning about processes and I've had trouble understanding them.
The program is designed to fork a tree of processes, however , I must fork from the root two processes which will fork , on the left side 3 children processes, and on the right side 4 children processes. These processes must fork 3 and 4, respectively, processes of their own.
My issue with this is that the program can fork the processes, however only one process on each side is fathering all of the children on their respective side.
Any help you could give me would be great, please tell me if I'm not being clear enough.
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
/* Prototypes */
void three_children();
void four_children();
int main()
{
pid_t process;
int status,n;
printf("Number of levels: \n");
scanf("%d", &n);
for (int i = 0; i < n ; i++) {
process = fork();
switch (process) {
case -1:
printf("Error\n");
break;
case 0:
if (i == 0) {
printf("Left\n");
three_children(process, status);
}
if (i == 1) {
printf("Right\n");
three_children(process, status);
}
printf("Hi I'm a child PID: %d, my father is PPID: %d\n", getpid(), getppid());
exit(0);
default:
printf("I'm a father PPID: %d\n", getppid());
break;
}
}
}
void four_children(pid_t process, int status)
{
for (int j = 0; j < 4; j++) {
process = fork();
switch (process) {
case -1:
printf("Error\n");
break;
case 0:
printf("I'm child: %d, and my father is: %d\n(four children)\n", getpid(), getppid());
exit(0);
break;
default:
printf("I'm a father process: %d\n", getpid());
four_children(process, status);
for (int j = 0; j < 3; j++) {
wait(&status);
}
break;
}
}
}
void three_children(pid_t process, int status)
{
for (int k = 0; k < 3; k++) {
process = fork();
switch (process) {
case -1:
printf("Error\n");
break;
case 0:
printf("I'm a child: %d, and my father is: %d\n(three children )\n", getpid(), getppid());
exit(0);
break;
default:
printf("I'm father %d\n", getpid());
three_child(process, status);
for (int j = 0; j < 3; j++) {
wait(&status);
}
break;
}
}
}

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
typedef struct Node
{
int childrenCount;
struct Node* child[0];
} Node;
Node* makeNode(int children)
{
Node* result = (Node*)malloc(sizeof(Node) + sizeof(Node*) * children);
if (!result) {
exit(1);
}
result->childrenCount = children;
for(int loop = 0;loop < children; ++loop) {
result->child[loop] = NULL;
}
return result;
}
void buildTree(int indent, pid_t parent, Node* node);
void createChild(int indent, pid_t parent, Node* node, int childIndex)
{
pid_t pid = fork();
if (pid == -1) {
exit(1);
}
if (pid == 0) {
buildTree(indent + 1, getpid(), node->child[childIndex]);
srand(parent * 10 + childIndex);
exit(rand());
}
for(int ind = 0; ind < indent; ++ind) {
fprintf(stderr, " ");
}
fprintf(stderr, "Parent: %d Spawned %d\n", parent, pid);
}
void buildTree(int indent, pid_t parent, Node* node)
{
for(int ind = 0; ind < indent; ++ind) {
fprintf(stderr, " ");
}
fprintf(stderr, "Parent %d Has %d Children\n", parent, node->childrenCount);
for(int loop = 0; loop < node->childrenCount; ++loop) {
createChild(indent, parent, node, loop);
}
for(int loop = 0; loop < node->childrenCount; ++loop) {
int status;
int child = wait(&status);
for(int ind = 0; ind < indent; ++ind) {
fprintf(stderr, " ");
}
fprintf(stderr, "Parent: %d Reaped %d with status %d\n", parent, child, status);
}
}
int main()
{
Node* root = makeNode(2);
root->child[0] = makeNode(3);
for(int loopChild = 0;loopChild < 3; ++loopChild) {
root->child[0]->child[loopChild] = makeNode(3);
for(int loopGrandChild = 0;loopGrandChild < 3; ++loopGrandChild) {
root->child[0]->child[loopChild]->child[loopGrandChild] = makeNode(0);
}
}
root->child[1] = makeNode(4);
for(int loopChild = 0;loopChild < 4; ++loopChild) {
root->child[1]->child[loopChild] = makeNode(4);
for(int loopGrandChild = 0;loopGrandChild < 4; ++loopGrandChild) {
root->child[1]->child[loopChild]->child[loopGrandChild] = makeNode(0);
}
}
fprintf(stderr, "Start\n");
buildTree(0, getpid(), root);
fprintf(stderr, "Stop\n");
}

Related

How to change order of creation of processes?

I have to make a tree of processes like in this image:
I have managed to create such a tree, but with a minor difference. P4 is actually P3, and P3 is P4. I have created them in order, because i can't think of a way of "attaching" P4 to P1, and P3 to P2. This is what I've written so far:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "a2_helper.h"
int main(int argc, char **argv){
printf("Main pid is %d\n", getpid());
pid_t pid1[2];
pid_t pid2[4];
pid_t pid3a, pid3b;
//FIRST LAYER
for(int i = 0; i < 2; i++){
pid1[i] = fork();
if(pid1[i] == 0){
printf("[son] pid %d from [parent] pid %d\n", getpid(), getppid());
//SECOND LAYER
if ( i == 0){
for(int j = 0; j < 4; j++){
pid2[j] = fork();
if (pid2[j] == 0){
printf("\t[son] pid %d from [parent] pid %d\n", getpid(), getppid());
//THIRD LAYER
if (j == 1){
pid3a = fork();
if (pid3a == 0){
printf("\t\t[son] pid %d from [parent] pid %d\n", getpid(), getppid());
exit(0);
}
waitpid(pid3a, NULL, 0);
}
if (j == 2){
pid3b = fork();
if (pid3b == 0){
printf("\t\t[son] pid %d from [parent] pid %d\n", getpid(), getppid());
exit(0);
}
waitpid(pid3b, NULL, 0);
}
//END THIRD LAYER
exit(0);
}
}
//END SECOND LAYER
for(int j = 0; j < 4; j++)
waitpid(pid2[j], NULL, 0);
}
exit(0);
}
}
for(int i = 0; i < 2; i++)
waitpid(pid1[i], NULL, 0);
//END FIRST LAYER
return 0;
}
What can I change in order to achieve that?
It's better for fork one fewer times than the paths you need. Look at the following code based on the graph (without P3 and P4 switched)
void doP1(){
if(fork())
doP2();
else
doP4();
}
void doP2(){
if(fork())
doP3();
else if(fork())
doP5();
else if(fork())
doP6();
else
doP7();
}
void doP3(){
return;
}
void doP4(){
return;
}
void doP5(){
doP8();
}
void doP6(){
doP9();
}
void doP7(){
return;
}
void doP8(){
return;
}
void doP9(){
return;
}
int main(){
doP1();
}
I separated every node of the tree into its own function which do nothing but fork in the way the graph shows.
When a data-path splits into two, you don't need to create two child threads, you just need to create one. The parent goes one way, and the child goes another.
i.e. P1 should only call fork once, P2 should only call fork three times, P5 and P6 shouldn't call fork at all
I hope that answers your question!

Capturing exit code of n child processes

I am trying to fork() 10 child processes in one loop and then in another loop wait() for them to terminate and print their PID along with their exit status code. It cannot be done any other way or using any other function. Two loops/waves and the function wait();
This is what I have tried:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t wait_p, p[10], p_child;
int status;
for (int i = 0; i < 10; i++)
{
p[i] = fork();
}
for (int i = 0; i < 10; i++)
{
switch (p[i])
{
case 0:
p_child = getpid();
exit(p_child % 10);
break;
case -1:
puts("ERROR");
break;
default:
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
break;
}
}
return (EXIT_FAILURE);
}
This code will execute an endless count of child processes. It must print only the first original(issued by THE one parent) 10. What am I doing wrong?
You have to handle the child processes directly in your first loop:
for (int i = 0; i < 10; i++)
{
p[i] = fork();
if (p[i] == 0) {
p_child = getpid();
exit(p_child % 10);
} else if (p[i] == -1) {
perror("fork");
}
}
and then wait for them in the second loop
for (int i = 0; i < 10; i++)
{
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
}
You cannot handle the case, that fork() returns in the child process (yielding 0 as return value), in your second loop, otherwise each child process in the first loop keeps forking more child processes.

Why the child process is not executed?

I have the following piece of code:
int main() {
int n = 1;
if(fork() == 0) {
printf("child");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%d: %d\n", getpid(), n);
wait(0);
return 0;
}
The problem is that I don't understand why the child process is not executing.
The child process is executing only if i set sleep(1) in the parent process
Thanks in advance.
It is getting executed and it should be outputting the text. No newlines should be necessary:
https://ideone.com/a1tznH
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int n = 1;
if(fork() == 0) {
printf("child");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%ld: %d\n", (long)getpid(), n); //this is how you should print pids
wait(0);
return 0;
}
Example output:
child23891: 3
Perhaps you didn't notice the child text was at the beginning of your next prompt:
18188: 3
child[21:17] pskocik#laptop: $
The child is executed but two processes are trying to write on the same FD - STDOUT (File Descriptor).
If you want to see the result, put "\n" in printf of the child.
int main() {
int n = 1;
if(fork() == 0)
{
printf("child\n");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%d: %d\n", getpid(), n);
wait(0);
return 0;
}
Try
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("fail to fork");
}
else if (pid == 0)
{
printf("running child");
exit(0);
}
else
{
print("running parent");
wait(0);
print("child done");
}
return 0;
This is the basic structure of a program I wrote recently which works. Not totally sure why yours didn't work though.

Matching int with element of int array in switch case

I'm getting the following error:
program.c:24:3: error: case label does not reduce to an integer constant
case proc_id[0]: //child process 1 pid
for all case statements in the following code:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int proc_id[4];
int main(int argc, char *argv[]){
int i;
int proc=1;
for (i = 0; i < 3; ++i)
{
if(proc != 0){
proc = fork();
}
if (proc != 0)
{
proc_id[i]=proc;
}
}
switch(getpid()){
case proc_id[0]: //child process 1 pid
for (i = 0; i < l; ++i)
{
alarm(3);
kill(proc_id[1], SIGUSR1);
}
break;
case proc_id[1]: //child process 2 pid
for (i = 0; i < l; ++i)
{
alarm(6);
kill(proc_id[2], SIGUSR2);
}
break;
case proc_id[2]: //child process 3 pid
for (i = 0; i < l; ++i)
{
alarm(9);
kill(proc_id[0], SIGUSR1);
}
break;
case proc_id[3]: //parent pid
printf("parent\n");
break;
}
return(0);
}
void custom_handler(int signum){
kill(SIGINT, getppid());
printf("PID:%d \t Signal Number: %d\n", getpid(), signum);
}
void parent_handler(int signum){
++sigcount;
switch(sigcount){
case l:
kill(proc_id[0], SIGTERM);
break;
case l+3:
kill(proc_id[1], SIGTERM);
break;
case l+6:
kill(proc_id[2], SIGTERM);
kill(proc_id[3], SIGTERM);
break;
}
}
void sigterm_handler(int signum){
exit(0);
}
I have two questions:
Why is this error occurring
and
Can we put an expression that evaluates to an integer as a case label?
Environment details:
Compiled program using gcc on ubuntu terminal.
switch labels are evaluated at compiling time, so it must be constant expressions. You cannot put an expression that evaluates to anything.
If you want an equivalent algorithm, you have to use an if statement
In
case proc_id[0]:
proc_id[0] is not a constant, it is a variable. The case label can only use a const such as:
case 10:
Similarly for the other case statements.
When you have a variable, your only option is to use if-else blocks.
int pid = getpid();
if ( pid == proc_id[0] )
{
for (i = 0; i < l; ++i)
{
alarm(3);
kill(proc_id[1], SIGUSR1);
}
}
else if ( pid == proc_id[1] )
{
for (i = 0; i < l; ++i)
{
alarm(6);
kill(proc_id[2], SIGUSR2);
}
}
else if ( pid == proc_id[2] )
{
for (i = 0; i < l; ++i)
{
alarm(9);
kill(proc_id[0], SIGUSR1);
}
}
else if ( pid == proc_id[3] )
{
printf("parent\n");
}

Function to create n child processes

int proc_create(int n)
{
int pid;
n = n+1;
printf("The parent process id: %d\n", getpid());
while(1)
{
if(pid=fork() < 0){
perror("Fork Failed!");
exit(1);
}else{
printf("The child process ID is: %d\n", pid);
}
}
}
I have written the above function that will create n child processes and each child processes will print out it's own child id. Can someone tell me the flaws and how i can improve the above function.
n is a local variable, so you just do n + 1 which doesn't change anything.
It creates infinite child processes, because the fork is inside a while(1) loop
int *proc_create(int n) {
int *childs = malloc(sizeof *childs * n);
printf("The parent process id: %d\n", getpid());
for (int i = 0; i < n; i++) {
int pid = fork();
if (pid < 0) {
perror("Fork Failed!");
exit(1);
} else if (pid == 0) {
return NULL;
} else {
childs[i] = pid;
printf("The child process ID is: %d\n", pid);
}
}
return childs;
}
This process spawn N children, when they return from proc_create() they will return NULL. The parent will return an array with the pids of its N children.

Resources