fork() and wait() in C - c

I am trying to learn the fork() and wait() system calls. If I run this code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main (){
printf("Hi, I am the parent with pid %d \n ",getpid());
int rc = fork();
printf("Fork returned : %d \n ",rc);
printf("I am the process with pid %d \n ",getpid());
wait(NULL);
return 0;
}
I get the output as expected on the terminal :
Hi, I am the parent with pid 3639
Fork returned : 3640
I am the process with pid 3639
Fork returned : 0
I am the process with pid 3640
However , If I remove wait(NULL) , I get a strange output on the terminal :
Hi, I am the parent with pid 3715
Fork returned : 3716
I am the process with pid 3715
John#John-VirtualBox:~/Fork5$ Fork returned : 0
I am the process with pid 3716
I totally understand that , we use wait() to make the parent process waits for the child to end executiion so that we can remove it from the process table and deallocate its PID . But here , if I remove the wait , we see that the terminal is called again :
John#John-VirtualBox:~/Fork5$ Fork returned : 0
I am the process with pid 3716
And even it doesn't return again back . I don't understand what this have to do with the functionality of wait ? Or in other words , why wait will fix this issue ?

The sequence of events appears to be:
The shell is the parent process to your program. When it forks your program your program inherits the standard streams (to the terminal).
Your program forks a child process which also inherits the standard streams (to the terminal).
When your parent process terminates, the shell notices (because it is waiting) and issues a prompt to the terminal.
However, your program’s child has not yet terminated, so after the shell issues its prompt the child prints its output (and then terminates).
You will notice that the shell does not issue a second prompt after the child terminates. (The shell does not know anything about your child process.)
Order of output
The fact that you get complete output lines (instead of anything interleaved) is because the standard streams for all processes are in line oriented mode.
However, there is no guarantee of order between processes. The OS scheduler can order them any way it wants. Your child could have printed before the parent.
:O)

Related

Why is sleep in a child process blocking my program?

So I have this simple program that sleeps for 4 second if the value returned by fork is '0' meaning that the child process is executing, I've tried using sleep in child process but the program is blocked, and flushing standard output isn't working...
code:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
pid_t value = fork();
if (value == 0) {
sleep(4);
}
printf("Value returned by fork: %d\n", value);
printf("I'm the process N°%d\n", getpid());
return 0;
}
I'm running on Ubuntu 20.04.3 LTS.
Output:
Value returned by fork: 12618
I'm the process N°12617\
farouk#farouk-HP-Pavilion-Desktop-TP01-1xxx:~/sysexp$ Value returned by fork: 0
I'm the process N°12618
To allow this question to have an accepted answer.
The child process is not blocking the shell. The shell gave its prompt and the child wrote some output after the prompt, leaving the cursor at the start of a line without a shell prompt visible — because the shell prompt already appeared earlier.
There are a variety of ways around this.
The simplest is just to type a command such as ps and hit return, noting that the shell executes it, and that the ps output does not list the child process. If you type the ps command quick enough, you might see the child listed in the output before its output appears.
Another is to modify the program so that it waits for all child processes to exit before it exits — using wait() or waitpid(). The same code can be used in the child and the parent since the child will have no children of its own. The call to the wait function will return immediately with a 'no more children' status (error).
You can find extensive discussion of all this in the comments — I've chosen to make this a Community Wiki answer since there was a lot of activity in the comments that identified the gist of this answer.

How does getpgid() work?

I'm trying to get the pid, the ppid and the pgid
and no matter what I do getpgid(pid) always gives me the pid.
At first, I was using it like this:
printf("PGID: %d", getpgid());
Then I realized, getpgid was taking a pid as argument so I did this:
printf("PGID: %d", getpgid(getpid()));
But this is still giving me the same number as the pid...
So I tried this:
pid_t pid;
pid = getpid();
printf("PGID: %d", getpgid(pid));
And this still doesn't work... Any idea why?
PS: I'm a beginner in c.
The process group leader is always the one that has pid == pgid, so perhaps you are making always the same test (on a process group leader) and this is the reason of getting always the same pgid as the pid of the process. When a process becomes a group leader, the kernel assigns it it's own pid as the pgid, so perhaps you are always getting that if you are checking in only one process. Bash uses process groups to distinguish background jobs and do job control, so every command you execute from a bash(1) shell will have a new process group and one of these processes (the only one if you only launched one process) will have the same the pgid and the pid of one of the processes of the job you are requesting.
The reason of this logic (to use the pid of the process group leader as the pgid) is to not have to deal with active process groups as no more groups than processed can be in the system... so when a new group id is needed the nearest process available is the own process that triggers the new process group creation, so assigning its own pid as pgid is no harmful.
For a simple example... just try the same program you used to demonstrate the pid and pgid values in a long pipe by piping them (you should try to print the output to stderr instead of stdout or all the outputs will get lost in the input buffer of the next process in the pipe):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pid = getpid();
fprintf(stderr, "pid=%d; pgid=%d\n", pid, getpgid(pid));
exit(EXIT_SUCCESS);
}
and then
$ testpgid | testpgid | testpgid
pid=3819; pgid=3819
pid=3820; pgid=3819
pid=3821; pgid=3819
$ testpgid | testpgid | testpgid
pid=3833; pgid=3833
pid=3835; pgid=3833
pid=3834; pgid=3833
getpid() returns the process ID of the current process.
When a process is running, the kernel schedules its runtime - especially it assigns a PID to it - such information is stored inside the kernel address space, in data structures (e.g. inside a task struct).
Thus, when a process calls the getpid() system call, the kernel just has to look in the task structure of the calling process.
It is a group ID of the process specified by pid.
Suppose if we consider pid as zero then the ID of the current process is used in it. getpgrp() and getpgid(0) are equivalent to each other.
e.g. pid_t getpgid(pid_t pid);

C - fork() and processes behaviour

I have a small program written in C on linux. It's purpose is to examine the behaviour of the fork() call and the resulting child processes
Upon first inspection everything seems simple enough. However
Sometimes output is written in a funny order
Sometimes the child PPID is '1' not whatever the parent PID is.
I can't find any pattern or correlation between when it works as expected and when it does not.
I think that point 2. is probably caused by the parent process dying before the child process has executed fully. If so, is there a way to stop this from happening.
However I have no idea what is causing point 1.
Code below:
#include <stdio.h>
#include <unistd.h>
int main()
{
int x = fork();
if (x == 0)
{
printf("Child:");
printf ("\nChild PID : %d", getpid());
printf ("\nChild PPID: %d", getppid());
printf("\nHello Child World\n");
}
if (x != 0)
{
printf("Parent :");
printf ("\nParent PID : %d", getpid());
printf ("\nParent PPID: %d", getppid());
printf("\nHello Parent World\n");
}
return 0;
}
this behaviour is seen because of scheduling policy of operating system. if you are aware of process management concepts of os, then if your parent code is running and fork() is encountered, child is created, but if within that time, parent's time slice has not been completed, then parent continues running and if within its time slice, parent executes and terminates, then child becomes orphan precess and after parent process' time slice completes, child's execution starts, thats why getppid() function returns 1, because child is an orphan process and it it now adopted by init process which starts first when operating system boots and is having process id 1.
Explanation of Behaviour 1:
The order of output cannot be controlled by the program normally. That's the point of parallel process. The OS decides which process to execute at any point of time and both processes are executed simultaneously (to the human eye).
Thus the output would generally be inter-tweened.
Explanation of Behaviour 2:
You guessed that right.
The parent process has finished before the forked one.
If you want the parent pid, you can use waitpid(x, &status, 0) in the parent process if you need the parent to stay alive till child execution. This link may help you.

Using fork() in C?

I have been asked this question for homework, and am having trouble figuring it out. If anyone can help me i would really appreciate it.
What Linux library function is like a fork(), but the parent process is terminated?
I'm fairly certain that whoever assigned you this homework is looking for the exec() family of functions, from the POSIX API header <unistd.h>, because there is nothing else that more closely resembles the sort of functionality you describe.
The exec() family of functions executes a new process and replaces the currently running process address space with the newly executed process.
From the man page:
The exec() family of functions replaces the current process image with
a new process image.
It's not exactly the same as "terminating" the parent process, but in practice it results in a similar situation where the parent process address space is erased (replaced) with the address space of the child process.
What Linux library function is like a fork(), but the parent process
is terminated?
The parent process should not terminate because , it must wait for the child processes to finish executing , after which they will be in a state called "zombie state", now it is the responsibility of the parent to clean up the leftovers of the child process. The parent process can terminate without cleaning up the child processes, but then, it is not a proper way to do it, as the exit status of the child processes should be collected and checked by the parent process.
Here is an example, to demonstrate , what i just said...
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
pid_t cpid = 1 ;
int status;
cpid = fork();
// Load a application to the child using execl() , and finish the job
printf("Parent waiting for child to terminate\n");
int wait_stat = waitpid(-1,&status,0); // Parent will hang here till all child processes finish executing..
if (wait_stat < 0)
{
perror("waitpid error");
exit(-1);
}
// WIFEXITED and WEXITSTATUS are macros to get exit status information, of the child process
if (WIFEXITED (status))
{
printf("Child of id %u cleaned up\n",wait_stat);
printf("Exit status of application = %u\n",WEXITSTATUS(status));
}
}

Why the output is printing twice?

May be it look childish for most of you but I am unable to understand this small piece of code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char** argv) {
int i, pid;
pid = fork();
printf("Forking the pid: %d\n",pid);
for(i =0; i<5; i++)
printf("%d %d\n", i,getpid());
if(pid)
wait(NULL);
return (0);
}
Out put of this program is
Forking the pid: 2223
0 2221
1 2221
2 2221
3 2221
4 2221
Forking the pid: 0
0 2223
1 2223
2 2223
3 2223
4 2223
Press [Enter] to close the terminal ...
In the for loop the printf command is used once. Why "Forking the pid" and after that the pid's are printed twice. How this is working? Can anybody explain me this? Thanks in advance.
Can anybody explain me why we have to use wait here? What I understood from the man pages is wait retuns the control to parent process? Is what I understood is correct?Is it necessary to use wait after forking a process?
Operating system : ubuntu, compiler : gcc, IDE : netbeans
But that' exactly what fork does. You forked the process and everything after the fork is done twice because now you have two processes executing the same printing code. You are basically asking why fork forks. fork forks because is is supposed to fork. That's what it's for.
After fork the parent and the child processes are generally executed in parallel, meaning that the nice sequential output you see in your example is not guaranteed. You might have easily ended up with line-interleaved output from two processes.
wait function in your case is executed from the parent process only. It makes it wait until the child process terminates, and only after that the parent process proceeds to terminate as well. Calling wait in this particular example is not really critical, since the program does nothing after that, it just terminates. But, for example, if you wanted to receive some feedback from the child process into the parent process and do some additional work on that feedback in the parent process, you'd have to use wait to wait for the child process to complete its execution.
The fork() call makes a new process. The rest of the code is then executed from each of the 2 processes. (Man page)
You're printing in both processes. Put your printing loop in an else clause of the if (pid):
pid = fork();
if(pid)
{
printf("Child pid: %d\n",pid);
wait(NULL);
}
else
{
for(i =0; i<5; i++)
printf("%d %d\n", i,getpid());
}
You see, fork returns twice, once in the parent process and once in the child process. It returns 0 in the child and the pid of the created process in the parent.
Because both the parent and child process are outputting their results.
See here: http://en.wikipedia.org/wiki/Fork_(operating_system)#Example_in_C for a good example.
fork creates a new process, and returns in both the old process (the parent) and in the new process (the child).
You can tell which one you are in by looking at the return value from fork. In the parent process it returns the PID of the child process. In the child process it return 0.

Resources