getting child process ID from the parent using C - c

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.

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 to visualise fork() in c

So I'm currently learning the fork() system call in C but I just can't seem to wrap my head around what exactly is happening.
This is the code
int id=fork();
int child_id, status;
//if id == 0 we are in the child process
if(id == 0 )
{
int pid = getpid()
printf("this is the child process %d\n", pid);
int id1=fork()
if(id1==0)
{
//this will return the pid of the grandparent
int pid2 = getppid();
printf("this is child no 2 process %d\n", pid2);
}
else
{
child_id = wait(&status);
printf("this is parent(%d) of child no 2\n", pid)
}
}
else
{
child_id = wait(&status);
printf("this is the parent process and we will execute after child %d\n", child_id);
}
And this is how I am visualizing it.

Grandchild process has PID 1 in C

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.

Create multiple generations of children process

So I'm trying to understand the concept of grandchildren.
I'm able to create a given number of sons (i.e brothers) but I don't know how to create multiple generations .
This is what I did to create one grandson :
int main ()
{
//Displaying the father
printf("Initial : Father = %d\n\n", getpid());
/****** FORK *******/
pid_t varFork, varFork2;
varFork = fork();
if(varFork == -1) //If we have an error, we close the process
{
printf("ERROR\n");
exit(-1);
}
else if (varFork == 0) //if we have a son, we display it's ID and it's father's
{
printf("SON 1\n");
printf(" ID = %d, Father's ID = %d\n", getpid(), getppid());
varFork2 = fork();//creation of the second fork
if(varFork2 == -1) //If we have an error, we close the process
{
printf("ERROR\n");
exit(-1);
}
else if (varFork2 == 0) //now we have the son of the first son, so the grandson of the father
{
printf("\nGRANDSON 1\n");
printf(" ID = %d, Father's ID = %d\n", getpid(), getppid());
}
else sleep(0.1);/*we wait 0.1sec so that the father doesn't die before we can
display it's id (and before the son process gets adopted by a user process descending from the initial process)*/
}
else //in the other case, we have a father
{
sleep(0.1);//again we put the father asleep to avoid adoption
}
return 0;
}
How can I create X generations of grandsons, X being a global variable (1son, 1 grandson, 1 great-grandson, etc.) ?
How can I create X generations
Before forking, decrement X and continue forking inside the child until X is 0.
Or inside the child decrement X and only continue forking if after decrementing it X still is greater 0.
The code might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
void logmsg(const char *, int);
#define MAX_GENERATIONS (4)
int main(void)
{
pid_t pid = 0;
for (size_t g = 0; g < MAX_GENERATIONS; ++g)
{
logmsg("About to fork.", 0);
switch (pid = fork())
{
case -1:
{
logmsg("fork() failed", errno);
break;
}
case 0:
{
logmsg("Hello world. I am the new child.", 0);
break;
}
default:
{
char s[1024];
snprintf(s, sizeof s, "Successfully created child carrying PID %d.", (int) pid);
logmsg(s, 0);
g = MAX_GENERATIONS; /* Child forked, so we are done, set g to end looping. */
break;
}
}
}
logmsg("Sleeping for 3s.", 0);
sleep(3);
if (0 != pid) /* In case we forked a child ... */
{
logmsg("Waiting for child to end.", 0);
if (-1 == wait(NULL)) /* ... wait for the child to terminate. */
{
logmsg("wait() failed", errno);
}
}
logmsg("Child ended, terminating as well.", 0);
return EXIT_SUCCESS;
}
void logmsg(const char * msg, int error)
{
char s[1024];
snprintf(s, sizeof s, "PID %d: %s", (int) getpid(), msg);
if (error)
{
errno = error;
perror(s);
exit(EXIT_FAILURE);
}
puts(s);
}
The output should look similar to this:
PID 4887: About to fork.
PID 4887: Successfully created child carrying PID 4888.
PID 4887: Sleeping for 3s.
PID 4888: Hello world. I am the new child.
PID 4888: About to fork.
PID 4888: Successfully created child carrying PID 4889.
PID 4888: Sleeping for 3s.
PID 4889: Hello world. I am the new child.
PID 4889: About to fork.
PID 4889: Successfully created child carrying PID 4890.
PID 4890: Hello world. I am the new child.
PID 4890: About to fork.
PID 4889: Sleeping for 3s.
PID 4890: Successfully created child carrying PID 4891.
PID 4890: Sleeping for 3s.
PID 4891: Hello world. I am the new child.
PID 4891: Sleeping for 3s.
PID 4888: Waiting for child to end.
PID 4890: Waiting for child to end.
PID 4891: Child ended, terminating as well.
PID 4890: Child ended, terminating as well.
PID 4887: Waiting for child to end.
PID 4889: Waiting for child to end.
PID 4889: Child ended, terminating as well.
PID 4888: Child ended, terminating as well.
PID 4887: Child ended, terminating as well.
The difference with my code above compared to the proposal I made is that it counts upwards to X.

Parent/Child process print

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.

Resources