I am trying to pass input from parent to child and then from child to grandchild with pipes. After that, the grandchild sends the result to the parent back and the parent will kill both processes.
I can do data passing with pipes but I guess I cannot kill processes because PID of the grandchild is seen as 1 by the parent.
Here is my code:
int main(){
if (pipe(fd) == -1) {
fprintf(stderr,"Pipe failed fd");
return 1;
}
if (pipe(sd) == -1) {
fprintf(stderr,"Pipe failed sd");
return 1;
}
if (pipe(td) == -1) {
fprintf(stderr,"Pipe failed sd");
return 1;
}
printf("Enter a number: ");
scanf("%s", write_msg);
pid_child = fork();
if (pid_child < 0) {
fprintf(stderr, "Fork failed child");
return 1;
}
if(pid_child > 0){ // parent
//pass data to child
close(fd[READ_END]);
write(fd[WRITE_END], write_msg, strlen(write_msg)+1);
close(fd[WRITE_END]);
wait(NULL);
close(td[WRITE_END]);
read(td[READ_END], read_msg_parent, strlen(read_msg_parent)+1);
printf("final output is: %s\n", read_msg_parent);
fflush(stdout);
close(td[READ_END]);
kill(pid_child);
printf("killed child with pid: %d\n" , pid_child);
kill(pid_grandc);
printf("killed grandchild with pid: %d\n" , pid_grandc);
} else { // child + grandchild
pid_grandc = fork();
if (pid_grandc < 0) {
fprintf(stderr, "Fork failed grand child");
return 1;
}
if(pid_grandc > 0){ // child
// get data from parent
close(fd[WRITE_END]);
read(fd[READ_END], read_msg_child, BUFFER_SIZE);
sscanf(read_msg_child, "%d", &x);
printf("Child: input %d and output %d\n", x, x*2);
fflush(stdout);
close(fd[READ_END]);
// pass data to grandchild
close(sd[READ_END]);
x *= 2;
sprintf(write_msg2, "%d", x);
write(sd[WRITE_END], write_msg2, strlen(write_msg2)+1);
close(sd[WRITE_END]);
wait(NULL);
exit(0);
} else { // grandchild
// get data from child
close(sd[WRITE_END]);
read(sd[READ_END], read_msg_grandchild, strlen(read_msg_grandchild)+1);
close(sd[READ_END]);
sscanf(read_msg_grandchild, "%d", &z);
printf("Grandchild: input %d, output: %d\n",z, z*2);
fflush(stdout);
z *= 2;
// pass data to child back
close(td[READ_END]);
sprintf(write_msg3, "%d",z);
write(td[WRITE_END], write_msg3, strlen(write_msg3) + 1);
close(td[WRITE_END]);
exit(0);
}
}
return 0;
}
And the sample output is:
> Enter a number: 12
> Child: input 12 and output 24
> Grandchild: input 24,output: 48
> final output is: 48
> killed child with pid: 7321
> killed grandchild with pid: 1
In your code, since the child is the one that creates grandchild process, the parent doesn't know the grandchild's pid.
I think you can pass the grandchild's pid by using an extra pipe.
after you check:
if(pid_grandc > 0){ // child
passGrandchildPid(newpipename, pid_grandc); // function to write pid to pipe
}
// ...
void passGrandchildPid(int newpipename[2], int pid_grandc){
int pid = grand_child_pid;
close(newpipename[0]); /* Close unused read end */
write(newpipename[1], &pid , sizeof(pid));
close(newpipename[1]);
fflush(stdout);
}
Then in the parent process, you can read the grandchild's process id from this new pipe and kill it.
Related
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
I have written a code that generates a random number in the child process using rand()... I need to send this random value to the parent process using pipe(). when I use read() and write () the values received by the parent is 0 instead of the random number.
I am getting no error just the output is Value received is : 0.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<fcntl.h>
int main ()
{
pid_t Cpid;
int fd[2];
int rVal;
//pid will store the value of fork()
Cpid = fork();
pipe(fd);
if( Cpid == 0)
{
//CHILD
rVal = rand()%100;
;
//this is in child process
close (fd[0]);
rVal = rand()%100;
write(fd[1], &rVal,sizeof (rVal));
close (fd[1]);
printf(" Child Pid : %d sending random value : %d to parent : %d\n",
getpid(), rVal, getppid());
}
else if(Cpid != 0 )
{
printf (" Parent PID : %d\n", getpid());
//this is the parent process
close(fd[1]);
read(fd[0], &rVal, sizeof(rVal));
printf(" value recieved is : %d\n", rVal);
close(fd[0]);
printf(" value recieved by parent : %d\n", rVal);
}
return 0;
}
The code should setup the pipe before forking the children. Otherwise, the parent and the children will use different pipes, and will not be able to talk to each other.
int main ()
{
pid_t Cpid;
int fd[2];
// Create the pipe BEFORE forking.
pipe(fd);
//pid will store the value of fork()
Cpid = fork();
if( Cpid == 0)
.. REST OF CODE ~~~
I'm start to studying the fork. while using the fork, I have some problems.
I'm trying to create a single parent process with two child
and two child trying to make each three grandchild.
When I run my code, unlike my expectations, so many child and grandchild come out.
Here my code:
int main()
{
int i, j, rev;
for(i=0;i<2;i++)
{
if((rev=fork())<0) { printf("fork() error\n"); exit(-1); }
else if(rev==0)
{
printf("child %d %d \n",getpid(),getppid());
for(j=0;j<3;j++)
{
if((rev=fork()) <0) { printf("fork() error\n"); exit(-1); }
else if(rev == 0)
{
printf("grandch %d %d \n",getppid(),getpid());
exit(0);
}
}
}
}
printf("parent %d %d \n",getpid(),getppid());
exit(0);
}
How can I correct this code?
One important example before using fork() statements :
//Calculate number of times hello is printed.
#include <stdio.h>
#include <sys/types.h>
int main()
{
fork();
fork();
fork();
printf("hello\n");
return 0;
}
Number of times hello printed is equal to number of process created. Total Number of Processes = 2^n where n is number of fork system calls. So here n = 3, 2^3 = 8.
fork (); // Line 1
fork (); // Line 2
fork (); // Line 3
L1 // There will be 1 child process
/ \ // created by line 1.
L2 L2 // There will be 2 child processes
/ \ / \ // created by line 2
L3 L3 L3 L3 // There will be 4 child processes
// created by line 3
So if you are trying to make two child process and then three grand
child follow something of this sort:
What you should do is something like this for two child processes
if(fork()) # parent
if(fork()) #parent
else # child2
else #child1
After you create process , you should check the return value. If you don't , the second fork() will be executed by both the parent process and the child process, so you have four processes.
If you want to create n child processes , just :
for (i = 0; i < n; ++i) {
pid = fork();
if (pid) { //means pid is non-zero value, i.e, pid>0
continue;
} else if (pid == 0) {
break;
} else {
printf("fork error\n");
exit(1);
}
}
The section of code that runs for the child processes doesn't exit. As a result, they continue on to run more iterations of the outer loop which only the parent process is supposed to run, so they spawn more children.
You need to call exit, or better yet _exit, so that the children don't do that:
int main()
{
int i, j, rev;
for(i=0;i<2;i++)
{
if((rev=fork())<0) { printf("fork() error\n"); exit(-1); }
else if(rev==0)
{
printf("child %d %d \n",getpid(),getppid());
for(j=0;j<3;j++)
{
if((rev=fork()) <0) { printf("fork() error\n"); exit(-1); }
else if(rev == 0)
{
printf("grandch %d %d \n",getpid(),getppid());
_exit(0);
}
}
sleep(1); // stick around so the grandchild can print the parent pid
_exit(0); // exit the child
}
}
printf("parent %d %d \n",getpid(),getppid());
sleep(1); // stick around so the child can print the parent pid
exit(0);
}
I'm writing a C program that creates a child process. After creating the child process, the parent process should ouput two messages: "I am the parent" then it should print "The parent is done". Same for child process "I am child" and "The child is done". However I want to make sure, the second message of the child is always done before the second message of the parent. How can I achieve to print "The child is done" and "The parent is done" rather than printing their pid?
#include <unistd.h>
#include <stdio.h>
main()
{
int pid, stat_loc;
printf("\nmy pid = %d\n", getpid());
pid = fork();
if (pid == -1)
perror("error in fork");
else if (pid ==0 )
{
printf("\nI am the child process, my pid = %d\n\n", getpid());
}
else
{
printf("\nI am the parent process, my pid = %d\n\n", getpid());
sleep(2);
}
printf("\nThe %d is done\n\n", getpid());
}
You could have a flag variable, that is set in the parent, but then the child clears it. Then simply check for that for the last output.
Something like
int is_parent = 1; // Important to create and initialize before the fork
pid = fork();
if (pid == -1) { ... }
if (pid == 0)
{
printf("\nI am the child process, my pid = %d\n\n", getpid());
in_parent = 0; // We're not in the parent anymore
}
else { ... }
printf("\nThe %s is done\n\n", is_parent ? "parent" : child");
Call wait(2) in the parent process for the child to complete.
else
{
wait(0);
printf("\nI am the parent process, my pid = %d\n\n", getpid());
}
You should check if wait() succeeds and main()'s return type should be int.
I'm trying to write a C program where I have one parent that create two childs.
My task is to retrieve the process ID of the parent of and both childs. For this I've been using getpid().
Now I've been asked to get the child information from the parent. I don't get how I can do this. Like how can I obtain the processing ID for a child from the parent?
I have this at the moment (simplified)
fork1 = fork();
if (fork1 < 0)
fork error
else if (fork1 == 0) {
child 1
use getpid()
use getppid()
} else {
fork2 = fork();
if (fork2 < 0)
fork error
else if (fork2 == 0) {
child 2
use getpid()
use getppid()
} else
parent again
}
After a minute of googling I found this page, where everything you need is written:
System call fork() is used to create processes. It takes no arguments and returns a process ID.
I highlighted the part which is importand for you, so you don't need to do anything to get the process IDs of the children. You have them already in fork1 and fork2!
Here is some code which will print the PIDs from parent and children.
#include <stdio.h>
int main() {
int fork1 = fork();
if (fork1 < 0) {
printf("error\n");
} else if (fork1 == 0) {
printf("I'm child 1\n");
printf("child 1: parent: %i\n", getppid());
printf("child 1: my pid: %i\n", getpid());
} else {
int fork2 = fork();
if (fork2 < 0) {
printf("error\n");
} else if (fork2 == 0) {
printf("I'm child 2\n");
printf("child 2: parent: %i\n", getppid());
printf("child 2: my pid: %i\n", getpid());
} else {
printf("I'm the parent\n");
printf("The PIDs are:\n");
printf("parent: %i\n", getpid());
printf("child 1: %i\n", fork1);
printf("child 2: %i\n", fork2);
}
}
return 0;
}
fork() returns two different values, it returns zero to the child and returns non-zero positive value to the parent, this value is the child process ID, so in your last else, fork1 is the pid of child1 and fork2 is the pid of child2.