Forking N processes in chain - c

I want to solve a certain problem and i can't figure it out how to do it properly. I have to create N processes in chain and after i finish making all of them, the initial process will random a number and write it in the pipe, the other processes read from the pipe the number, they randomize a number and substract the result from the number read, write it back to the pipe and so on. Here is what i've tried
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define P_READ 0
#define P_WRITE 1
void forker(int nprocesses, int** pipes, int fd[2])
{
pid_t pid;
int buf;
if(nprocesses > 0)
{
if ((pid = fork()) < 0)
{
perror("fork");
}
else if (pid == 0)
{
//Child
printf("Child %d created PID : %d , PPID : %d\n", nprocesses-1, getpid(), getppid());
int i = nprocesses - 1;
time_t t;
srand((int)time(&t) % getpid()); // get unique seed for every child
int r = (rand() % 11) + 10;
if (i==0) {
read(fd[P_READ], &buf, sizeof(int));
close(fd[P_READ]);
}else{
read(pipes[i-1][P_READ], &buf, sizeof(int));
close(pipes[i-1][P_READ]);
}
close(pipes[i][P_READ]);
buf -= r;
printf("%d|%d|%d|%d\n", buf, r, getpid(), getppid());
write(pipes[i][P_WRITE], &buf, sizeof(int)); // write
close(pipes[i][P_WRITE]);
printf("Child %d end\n", nprocesses-1);
}
else if(pid > 0)
{
forker(nprocesses - 1, pipes, fd);
}
}
}
int main (void)
{
int status = 0;
srand(time(NULL));
pid_t pid = getpid();
pid_t parent = getpid();
pid_t wpid;
int n, fd[2], buf;
printf("Please enter how many processes you want(between 6 and 15): ");
scanf("%d", &n);
while ( n < 6 || n > 15)
scanf("%d", &n);
int **pipes = (int **)malloc(n * sizeof(int*));
for(int i = 0; i < n; i++) pipes[i] = (int *)malloc(2 * sizeof(int));
printf("I'm parent - my pid is %d\n",pid);
pipe(fd);
for(int i=0; i<n; i++) {
if(pipe(pipes[i])) {
printf("pipe error");
return -1;
}
}
forker(n, pipes, fd);
if(parent == getpid()) {
close(fd[P_READ]);
buf = (rand() % 9001) + 1000;
printf("The initial number is %d created by process with pid : %d\n", buf, getpid());
write(fd[P_WRITE], &buf, sizeof(int));
close(fd[P_WRITE]);
}
while ((wpid = wait(&status)) > 0); // WAIT
if (pid == getpid()) printf("End of parent and my pid was %d\n", pid);
return 0;
}
The output looks something like this :
Please enter how many processes you want(between 6 and 15): 10
I'm parent - my pid is 3827
Child 9 created PID : 3828 , PPID : 3827
Child 8 created PID : 3829 , PPID : 3827
Child 7 created PID : 3830 , PPID : 3827
Child 6 created PID : 3831 , PPID : 3827
Child 5 created PID : 3832 , PPID : 3827
Child 2 created PID : 3835 , PPID : 3827
Child 3 created PID : 3834 , PPID : 3827
The initial number is 1625 created by process with pid : 3827
Child 1 created PID : 3836 , PPID : 3827
Child 4 created PID : 3833 , PPID : 3827
Child 0 created PID : 3837 , PPID : 3827
1609|16|3837|3827
Child 0 end
1589|20|3836|3827
1573|16|3835|3827
Child 2 end
1559|14|3834|3827
Child 3 end
1543|16|3833|3827
Child 4 end
1530|13|3832|3827
Child 5 end
Child 1 end
1511|19|3831|3827
Child 6 end
1498|13|3830|3827
Child 7 end
1488|10|3829|3827
Child 8 end
1470|18|3828|3827
Child 9 end
End of parent and my pid was 3827
The problem is that, i am not sure if the first number is randomed before the processes creation(but that's not the big issue here). The big issue is that the initial process creates all the child processes and it is not "in chain".

First fork you process N times, then generate the random number and pass it to other process.
So put the creation of the random number outside the loop for forking the main process

Related

Using fork() and execlp() to create process hierarchy in C

I MUST use fork() and execlp() to create and annotate the given process hierarchy:
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, add to that the non-negotiable use of execlp() which replaces the current process image.
Here is what I managed to come up with (please excuse the very non-DRY code, I'm new to these concepts):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define oops(m) {perror(m); exit(EXIT_FAILURE);}
int main() {
pid_t pid1_1, pid1_2, pid1_1_1, pid1_1_2, pid1_2_1, pid1_2_2;
pid1_1 = fork();
if (pid1_1 < 0) {
oops("Fork Failed!");
}
// child 1.1
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.1.1
pid1_1_1 = fork();
if (pid1_1_1 < 0) {
oops("Fork Failed!");
}
if (pid1_1_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.1", NULL) < 0)
oops("Execlp Failed!");
}
//grandchild 1.1.2
pid1_1_2 = fork();
if (pid1_1_2 < 0) {
oops("Fork Failed!");
}
if (pid1_1_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.1.2", NULL) < 0)
oops("Execlp Failed!");
}
}
pid1_2 = fork();
if (pid1_2 < 0) {
oops("Fork Failed!");
}
// child 1.2
if (pid1_2 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.2", NULL) < 0)
oops("Execlp Failed!");
} else {
// grandchild 1.2.1
pid1_2_1 = fork();
if (pid1_2_1 < 0) {
oops("Fork Failed!");
}
if (pid1_2_1 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.1", NULL) < 0)
oops("Execlp Failed!");
}
// grandchild 1.2.2
pid1_2_2 = fork();
if (pid1_2_2 < 0) {
oops("Fork Failed!");
}
if (pid1_2_2 == 0) {
printf("I am the grandchild %d\n", getpid());
if (execlp("./iam", "iam", "1.2.2", NULL) < 0)
oops("Execlp Failed!");
}
}
// pid > 0 ==> must be parent
printf("I am the parent %d\n", getpid());
/* parent will wait for the child to complete */
if (waitpid(-1, NULL, 0) < 0)
printf("-1 from wait() with errno = %d\n", errno);
printf("Child terminated; parent exiting\n");
exit(EXIT_SUCCESS);
}
My output shows that this hierarchy is not set up correctly. For example, manually stepping through with gdb and finishing the PID for 1.2 terminates the entire process tree (when 1.1 sub-tree should be left in tact).
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated. Thanks!
Any suggestions for where I'm going wrong with logically replicating this process hierarchy would be really appreciated.
Check this part of code at start of your program:
pid1_1 = fork();
this will fork a child process. After this you are doing:
if (pid1_1 == 0) {
printf("I am the child %d\n", getpid());
if (execlp("./iam", "iam", "1.1", NULL) < 0)
......
That means, now the child process image will be replaced by another process image.
As per picture you have shown, a process is supposed to fork 2 child process before calling execlp(), if it is a parent process in the given process tree. Similar kind of problems are there in below part of your code.
I cannot wrap my head around when each process should be forked in order to reflect this hierarchy, .....
Look at the process tree closely and you will find it as a perfect binary tree where every internal node has 2 child and all leaf nodes are at same level.
That said, every process should create 2 child process and then call execlp() and as soon as you reach to the given height (which is 2 in your case), no child process should fork further.
I will show you how to create the process hierarchy and you can add the execlp() call to replace the current process image with some other process image.
add to that the non-negotiable use of execlp() which replaces the current process image.
I believe, here, the current process means the process which is forking of child processes and this includes the top most process (equivalent to root in tree) as well.
To create the hierarchy of process as perfect binary tree, you can do:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char *argv[]) {
int height;
if (argc != 2) {
printf ("Invalid number of arguments, exiting..\n");
exit (0);
}
height = atoi (argv[1]);
if (height < 0) {
printf ("Invalid input.\n"); // error handling can be better
exit (0);
}
printf ("Parent process, my pid = %d, height = %d\n", getpid(), height);
for (int i = 0; i < height; ++i) {
printf ("\nMy pid : %d, current height of tree : %d, forking..\n", getpid(), i);
pid_t pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 1..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
pid = fork();
if (pid == -1) {
printf ("Fork failed\n");
} else if (pid == 0) {
printf ("My pid = %d, [my parent : %d], I am child 2..\n", getpid(), getppid());
// this sleep is for sequenced output, otherwise it's not needed
// sleeping for 1 second
sleep (1);
continue;
}
// break the loop as the current process is done with forking 2 child process
break;
}
// ADD execlp call here
// This part of code is to just show you the hierarchy.
// If you add execlp call above then part is not needed.
while (wait(NULL) > 0);
printf ("pid %d : I am EXITING\n", getpid());
// added sleep for sequenced output, otherwise it's not needed
sleep (1);
return 0;
}
Usage: ./a.out <height_of_process_tree>
Output:
# ./a.out 0
Parent process, my pid = 50807, height = 0
pid 50807 : I am EXITING
# ./a.out 1
Parent process, my pid = 50808, height = 1
My pid : 50808, current height of tree : 0, forking..
My pid = 50809, [my parent : 50808], I am child 1..
My pid = 50810, [my parent : 50808], I am child 2..
pid 50810 : I am EXITING
pid 50809 : I am EXITING
pid 50808 : I am EXITING
# ./a.out 2
Parent process, my pid = 50811, height = 2
My pid : 50811, current height of tree : 0, forking..
My pid = 50812, [my parent : 50811], I am child 1..
My pid = 50813, [my parent : 50811], I am child 2..
My pid : 50812, current height of tree : 1, forking..
My pid : 50813, current height of tree : 1, forking..
My pid = 50814, [my parent : 50812], I am child 1..
My pid = 50815, [my parent : 50813], I am child 1..
My pid = 50816, [my parent : 50812], I am child 2..
My pid = 50817, [my parent : 50813], I am child 2..
pid 50814 : I am EXITING
pid 50815 : I am EXITING
pid 50816 : I am EXITING
pid 50817 : I am EXITING
pid 50812 : I am EXITING
pid 50813 : I am EXITING
pid 50811 : I am EXITING

How can I create three child processes by a child process?

I want to create three child processes from a child process of the main process (P0). So something like -->
P0 -> P1 ->P2
->P3
->P4
However, whenever I run it I get (for the processes P2,P3,P4) the ppid of the main process (ppid = 1).
I am using fork() system call in order to create the children and the implementation of the program is in C.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int i, pid1, pid2;
pid1 = fork();
printf("Pid1 pid -> %d ppid -> %d\n",getpid(),getppid());
if(pid1 != 0)
{
pid2 = fork();
printf("Pid2 pid -> %d ppid -> %d\n",getpid(),getppid());
if(pid2 == 0)
{
for(i=2; i<5; i++)
{
//if(fork()==0)
//{
printf("Child %d pid -> %d Parent -> %d\n",i+1,getpid(),getppid());
//}
exit(0);
}
}
else
{
printf("Pid2 father process \n");
}
}
else
{
printf("Pid1 child process\n");
}
}
You want something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int i, pid1, pid2;
pid1 = fork();
printf("Pid1 pid -> %d ppid -> %d\n",getpid(),getppid());
// parent
if(pid1 != 0)
{
pid2 = fork();
printf("Pid2 pid -> %d ppid -> %d\n",getpid(),getppid());
if(pid2 == 0)
{
for(i=2; i<5; i++)
{
if(fork()==0)
{
printf("Child %d pid -> %d Parent -> %d\n",i+1,getpid(),getppid());
// some functionality here
exit(0);
}
}
exit(0);
}
else
{
printf("Pid2 father process \n");
}
}
else
{
printf("Pid1 child process\n");
}
}
Giving the following output in my machine:
Pid1 pid -> 17764 ppid -> 32242
Pid1 pid -> 17765 ppid -> 17764
Pid1 child process
Pid2 pid -> 17764 ppid -> 32242
Pid2 father process
Pid2 pid -> 17766 ppid -> 17764
Child 3 pid -> 17767 Parent -> 17766
Child 4 pid -> 17768 Parent -> 17766
Child 5 pid -> 17769 Parent -> 17766
Thus, with the following hierarchy:
Parent (pid: 17764) -> C1 (17765) -> C2 -> 17666
C3-> 17767
C4-> 17768
C5-> 17769
Warning, in
pid1 = fork();
printf("Pid1 pid -> %d ppid -> %d\n",getpid(),getppid());
the printf is done both in P0 and P1, this is unclear at all, you have first to check pid1 before to print where you are.
Warning, in
pid1 = fork();
...
if(pid1 != 0)
{
pid2 = fork();
you supposed to be in P1 when you fork again, but you are still in P0 because pid1 is not 0
It is also recommended to check fork success (return value is not -1), and wait for the child(ren) termination rather than to exit the parent process before
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int pid1 = fork();
if (pid1 == -1)
perror("cannot fork p1");
else if(pid1 != 0)
{
int pid2;
printf("In P1, Pid1 pid -> %d ppid -> %d\n", getpid(), getppid());
pid2 = fork();
if (pid2 == -1)
perror("cannot fork p2");
else if (pid2 == 0) {
int pid3[2];
int i;
printf("in P2, Pid2 pid -> %d ppid -> %d\n", getpid(), getppid());
for (i = 0; i != 2; ++i) {
pid3[i] = fork();
if (pid3[i] == -1)
perror("cannot fork P2 child");
else if (pid3[i] == 0) {
printf("in Child %d pid -> %d Parent -> %d\n",i+1,getpid(),getppid());
return 0;
}
else
puts("in p2");
}
waitpid(pid3[0], 0, 0); /* erroned if fork failed, whatever */
waitpid(pid3[1], 0, 0); /* erroned if fork failed, whatever */
}
else {
puts("still in p1");
waitpid(pid2, 0, 0);
}
}
else
{
puts("in P0");
waitpid(pid1, 0, 0);
}
return 0;
}
Compilation and execution :
/tmp % ./a.out
In P1, Pid1 pid -> 68995 ppid -> 54669
in P0
still in p1
in P2, Pid2 pid -> 68997 ppid -> 68995
in p2
Child 1 pid -> 68998 Parent -> 68997
in p2
Child 2 pid -> 68999 Parent -> 68997
/tmp %
Note the written pid are wrong, from the manual of getppid :
then a call to getpid() in the child will return the wrong value (to be precise: it will return the PID of the parent process)

Parent process to monitore and fork new child processes depending on exit status

I've created the below code:
int main(int argc, char *argv[])
{
int i, n, N;
pid_t pid;
int status;
N = atoi(argv[1]);
for(i = 0; i < N; i++) {
pid = fork();
if(pid==0) {
srand(getpid() * getppid());
n = rand() % 10 + 1;
printf("I'm child nÂș %d with childpid %d, parent pid = %d, n = %d\n", i, getpid(), getppid(), n);
exit(n);
}
}
while ((pid = waitpid(pid, &status, 0))) {
if (pid < 0)
;
else if (WEXITSTATUS(status) < 4)
printf("exit status %d lower than 4\n", WEXITSTATUS(status));
}
wait(NULL);
return 0;
}
The idea is a parent process forking N child process and each of them exiting with a random value. I want my parent process to monitor all the child processes and fork a new child if the exit status is, for instance <4. This will be going on until all process exit with a status >= 4.
Solved creating a function copying the code from parent and child (keeping the code in main() untouched). The parent calls the function, the function forks another process, and the parent in the same function calls the function recursively under the conditions we choose.

Multiple 1-to-1 pipes in C

Is it possible in C to have multiple concurrent 1-to-1 pipes?
My example use case is the following:
The parent creates x children processes using fork()
The parent creates x pipes, one for each child
Each child write to its respective pipe, then closes it.
The parent reads from the pipes then closes them.
My current draft attempt is as follows however I have doubts about its functionality:
// Create x pipes
int fd[2*x];
pipe(fd);
// In child i do (i from 0 to x-1 inclusive):
close(fd[2*i]);
write(fd[2*i +1], .....);
close(fd[2*i +1]);
// In parent do:
wait() // wait for children to finish
// while any pipe has content do:
// For each i from 0 to x-1 inclusive:
close(fd[2*i +1]);
read(fd[2*i], .....);
close(fd[2*i]);
I would really appreciate it if someone could show me a simple example of this concept at work. The end goal here is one way conversations between children to parent with multiple values that the parent will store into a single array.
This code more or less does what you want. It uses error reporting code that is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.
#include "stderr.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
enum { NUM_CHILDREN = 5 };
enum { MSG_BUFFSIZE = 64 };
static void be_childish(int kid, int *fd);
int main(int argc, char **argv)
{
int fd[2 * NUM_CHILDREN];
int pid[NUM_CHILDREN];
err_setarg0(argv[0]);
err_setlogopts(ERR_PID);
if (argc != 1)
err_usage("");
for (int i = 0; i < NUM_CHILDREN; i++)
{
if (pipe(&fd[2 * i]) != 0)
err_syserr("failed to create pipe for child %d: ", i);
}
for (int i = 0; i < NUM_CHILDREN; i++)
{
if ((pid[i] = fork()) < 0)
err_syserr("failed to fork child %d: ", i);
else if (pid[i] == 0)
be_childish(i, fd);
else
{
printf("Child %d has PID %d\n", i, pid[i]);
fflush(stdout);
}
}
char buffer[MSG_BUFFSIZE];
for (int i = 0; i < NUM_CHILDREN; i++)
{
close(fd[2 * i + 1]);
int pipe_in = fd[2 * i + 0];
int nbytes = read(pipe_in, buffer, sizeof(buffer));
if (nbytes < 0)
err_syserr("failed to read from FD %2d: ", pipe_in);
printf("Got %2d bytes [%.*s] from FD %2d, PID %d\n",
nbytes, nbytes, buffer, pipe_in, pid[i]);
close(pipe_in);
}
for (int i = 0; i < NUM_CHILDREN; i++)
{
int status;
int corpse = wait(&status);
if (corpse > 0)
printf("Child with PID %d exited with status 0x%.4X\n", corpse, status);
else
err_syserr("Failed to wait for dead children: ");
}
return 0;
}
static void be_childish(int kid, int *fd)
{
for (int i = 0; i < kid; i++)
{
close(fd[2 * i + 0]);
close(fd[2 * i + 1]);
}
close(fd[2 * kid + 0]);
int estat = kid + 32;
char buffer[MSG_BUFFSIZE];
int nbytes = snprintf(buffer, sizeof(buffer),
"Child %d (PID %d) exiting with status %d",
kid, (int)getpid(), estat);
int pipe_out = fd[2 * kid + 1];
if (write(pipe_out, buffer, nbytes) != nbytes)
err_syserr("failed to write to parent: ");
close(pipe_out);
exit(estat);
}
Sample run:
Child 0 has PID 36957
Child 1 has PID 36958
Child 2 has PID 36959
Child 3 has PID 36960
Child 4 has PID 36961
Got 42 bytes [Child 0 (PID 36957) exiting with status 32] from FD 3, PID 36957
Got 42 bytes [Child 1 (PID 36958) exiting with status 33] from FD 5, PID 36958
Got 42 bytes [Child 2 (PID 36959) exiting with status 34] from FD 7, PID 36959
Got 42 bytes [Child 3 (PID 36960) exiting with status 35] from FD 9, PID 36960
Got 42 bytes [Child 4 (PID 36961) exiting with status 36] from FD 11, PID 36961
Child with PID 36960 exited with status 0x2300
Child with PID 36959 exited with status 0x2200
Child with PID 36958 exited with status 0x2100
Child with PID 36957 exited with status 0x2000
Child with PID 36961 exited with status 0x2400

Wait() runs twice?

In my code below, I'm running a parent process which forks off into two child processes. After child(getpid());, both children exit with a status.
However, when I run the parent process, it somehow always decides to run the parent section twice (sets two different pid values), and I just can't get it to run just once. Is there a way to make wait stop after getting one value?
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
void child(int n) { //n: child pid
printf("\nPID of child: %i \n", n);
//random number rand
int randFile = open("/dev/random", O_RDONLY);
int r;
if(rand < 0)
printf("ERROR: %s\n", strerror(errno));
else {
unsigned int seed;
read(randFile, &seed, 4); //&rand is a pointer, 4 bytes
int randClose = close(randFile);
srand(seed); //seeds rand() with random from /dev/random
r = rand();
if(randClose < 0)
printf("ERROR: %s\n", strerror(errno));
//range between 5 and 20 seconds
r = r % 20;
if( r < 5)
r = 5;
}
// printf("\n%i\n", r);
sleep(r);
// sleep(1);
printf("\n child with pid %i FINISHED\n", n);
exit( r );
}
int main() {
printf("\nPREFORK\n");
int parentPID = getpid();
int child0 = fork();
if(child0 < 0)
printf("ERROR: %s\n", strerror(errno));
int child1 = fork();
if(child1 < 0)
printf("\nERROR: %s\n", strerror(errno));
if(getpid() == parentPID)
printf("\nPOSTFORK\n");
//if children
if(child1 == 0) //using child1 as child-testing value b/c when child1 is set, both children are already forked
child(getpid());
int status;
int pid = wait(&status);
//parent
if(getpid() != 0) {
if( pid < 0)
printf("\nERROR: %s\n", strerror(errno));
if ( pid > 0 && pid != parentPID) {
printf("\nPID of FINISHED CHILD: %i\n Asleep for %i seconds\n", pid, WEXITSTATUS(status));
printf("PARENT ENDED. PROGRAM TERMINATING");
}
}
return 0;
}
The parent is doing:
int child0 = fork(); // + test if fork failed
int child1 = fork(); // + test if fork failed
First you only have the parent.
After 1st fork you have the parent and the 1st child, both at the same execution point, so just before the next fork.
So just after that the parent re-creates a child, and the 1st child creates its own child (and will act like the parent).
You have to use if/else so that you are sure that the child don't fork. i.e.:
child0 = fork(); // add check for errors
if (child0 == 0) {
// the 1st child just have to call that
child(getpid());
exit(0);
}
// here we are the parent
child1 = fork();
if (child1 == 0) {
// the 2nd child just have to call that
child(getpid());
exit(0);
}
You can do that differently, of course, this is just an example. The main point is to not call fork() within the child.

Resources