I write the following codes and run it in my linux.Everytime after fork the terminals print two PID, which shows both processes are scheduled by the OS, and then it is time for "scanf" to execute, both processes are blocked waiting for the input.However every time I put a number, and then I get the same PID printed on the terminal. Does it mean the same process is invoked by the OS when a terminal IO meets, or something else happens?
int main(int argc, char* argv[])
{
int num;
if(fork() >= 0)
{
printf("%x\n",getpid());
while(1)
{
if(scanf("%d",&num) != EOF)
{
printf("%x\n",getpid());
}
}
}
printf("\nit is over:%x\n", getpid());
}
As Hunter McMillen already noted in comments you are grouping the cases for the parent and child. Now both of them are scheduled as noted by different PIDs outputted and both of them are now waiting at scanf. As soon as you enter data, you are seeing only one PID, because the input you entered was part of one process. Other process ( can be parent or child ) is still waiting for you to enter something. Now, even though your terminal is flooded by a single PID, continuously outputted by one process, try entering some data again and press enter. Now you can see both PIDs being printed!
This is because, in the if() statement, fork() creates child process and runs in an infinite loop. There's a concept of parent process, the parent of child process created using fork() system call. The statement after if() ends, belongs to parent process and here, it will execute only after child process ends. That's why you get the same process ID, that is of child process.
Related
The output of the program are not obviously contents from the printf()s in teh code. Instead it looks like characters in irregular sequence. I know the reason is because the parent process and child process are running
at the same time, but in this program I only see pid=fork(), which I think means pid is only the id of child process.
So why can the parent process print?
How do the two processes run together?
// fork.c: create a new process
#include "kernel/types.h"
#include "user/user.h"
int
main()
{
int pid;
pid = fork();
printf("fork() returned %d\n", pid);
if(pid == 0){
printf("child\n");
} else {
printf("parent\n");
}
exit(0);
}
output:
ffoorrkk(()) rreettuurrnende d 0
1c9h
ilpda
rent
I focus my answer on showing how the observed output can result from the shown program. I think that it will already clear things up for you.
This is your output.
I edited it to use a good guess of what is parent (p) and child (c):
ffoorrkk(()) rreettuurrnende d 0\n
cpcpcpcpcpcpcpcpcpcpcpcpccpcpcppccc
1 c9h\n
pccpcpp
ilpda\n
ccpcpcc
rent
pppp
If you only use the chars with a "c" beneath, you get
fork() returned 0
child
If you only use the chars with a "p" beneath, you get
fork() returned 19
parent
Split that way, it should match what you know about how fork() works.
Comments already provided the actual answer to the three "?"-adorned questions in title and body of your question post.
Lundin:
It creates two processes and they are executed just as any other process, decided by the OS scheduler.
Yourself:
each time fork() is called it will return twice, the parent process will return the id of child process, and child process will return 0
Maybe for putting a more obvious point on it:
The parent process receives the child ID and also continues executing the program after the fork().
That is why the output occurs twice, similarily, interleaved, with differences in PID value and the selected if branch.
Relevant is also that in the given situation there is no line buffering. Otherwise there would be no character-by-character interleaving and everthing would be much more readable.
According to my knowledge, the child process executes first. Why the parent process was executed before the child and the parent was executed again? How did the execution process went from parent to child to parent again? And why should the pipe be closed? I tried the code without the close pipe statement and I got the same output.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void main(){
int P1P2[2];
int P2P1[2];
pipe(P1P2);
pipe(P2P1);
int x,y;
if(fork()){ // father
close(P1P2[0]);
close(P2P1[1]);
printf("Enter one integer:");
scanf("%d",&x);
write(P1P2[1], &x, sizeof(x));
read(P2P1[0], &y, sizeof(y));
printf("Multiplication is %d\n", y);
}
else{ // Child
close(P1P2[1]);
close(P2P1[0]);
read(P1P2[0], &x, sizeof(x));
y = x*x;
write(P2P1[1], &y, sizeof(y));
}
}
output:
abbas#abbas-VirtualBox:~/Desktop$ ./simplle
Enter one integer:4
Multiplication is 16
After calling fork, there are two processes that run independently from each other. The processor switches between them like it does with other separate processes, so you won't always get the same behavior.
If you did want the parent to wait for the child to finish, you could use waitpid.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void){
int P1P2[2];
int P2P1[2];
pipe(P1P2);
pipe(P2P1);
int x,y;
if( fork() > 0 ){ // parent
close(P1P2[0]);
close(P2P1[1]);
printf("Enter one integer:");
scanf("%d",&x);
write(P1P2[1], &x, sizeof(x)); /* (2) */
read(P2P1[0], &y, sizeof(y)); /* (3) */
printf("Multiplication is %d\n", y);
} else { // Child (or pipe error)
close(P1P2[1]);
close(P2P1[0]);
read(P1P2[0], &x, sizeof(x)); /* (1) */
y = x*x;
write(P2P1[1], &y, sizeof(y)); /* (4) */
}
}
Suppose the child is running immediately after the fork, and the parent is not. The child will block on the read at (1), waiting for data. Since there is no data, it will yield the cpu. At some point in the future, the parent will be scheduled and will execute printf, scanf and write. After the parent has written into the pipe at (2), either the child or the parent may execute in any order. Eventually, the parent will block on the read at (3) and will not be able to proceed until the child writes at (4). So the pipe works to synchronize the processes.
According to my knowledge, the child process executes first. Why the parent process was executed before the child and the parent was executed again? How did the execution process went from parent to child to parent again? And why should the pipe be closed? I tried the code without the close pipe statement and I got the same output.
Your knowledge is not correct. You don't know who is going to be scheduled first, if the parent or the child. Both cases can happen. The parent is normally free to run after the system call has checked all possible errors, while the child still has to build a complete environment to run. So it is very possible for the parent to run first.
The execution normally get's like this. The parent calls fork() which in turn switches to kernel mode. Here, the parent process (there's still no child anywhere) checks all conditions necessary to create a child process, enough resources, not trespassing of limits, etc. and if everything gets ok, then it creates a new process entry in the processes table. Once this is done, the parent kernel code has all the elements to start running a second kernel thread and starts it, to execute the second part of the fork call, while the first (the parent process) already has the return code of the system call and is ready to run (this means that the child process will be executed, not failing to do that, but it doesn't need to be immediately). From this point on, the parent process can return from kernel mode with the child pid, and continue, while the child kernel has still to build enough context to run and be scheduled. This can happen very quickly, even before the scheduler has had the time to reschedule the parent again, so the conclussion is that you don't know which one is to continue executing user code first.
In respect to your second question, the order of execution from the fork() onwards depends on so many things that is actually unpredictable. Both are different processes and execute as soon as the system allows them to proceed.
In respect to the closing of the pipes, you can do it or you cannot.... as you prefer... but a pipe works passing all the data from the writer process to the reader, until the pipe gets its last close(2) When you fork()ed, the system passed of having two pipes, with four file descriptors to have 4 (two on the parent, two on the child) with a total of eight file descriptor (four readers and four writer descriptors, two for each process) (and this means that both writers, the parent process and the child process, need to close(2) the writing side of the pipe for the readers --again, both the father and the child-- to receive the corresponding EOF indicating that the other end has closed its side) This is of no concern to you (I mean, doesn't show any difference) because you have limited your protocol to just one message in each direction, and there's no EOF condition to be waited for.... but try extending your sample code to read from the pipe until it closes it side, and you will see the difference (in that case, without having closing your writer side, your process will block waiting for input, and no input is received because the other process has closed the descritptor and the only process waiting for input is the only process that can write on it).
"When we call fork() on a process and its child is created, it is said that the point of execution starts from the point next to the fork() call in both the processes. But when I checked,
main() {
printf("hello");
val =fork();
if(val==0){
printf("child");
}
if(val>0){
printf("parent");
}
}
This program printed hello also twice. I am a little confused. Please help me out.
When you do printf("hello");, the output is line buffered for STDOUT which is not flushed. Now when the buffer still containing data, fork() call makes both parent and child process inherit data present in the buffer making it print twice.
Ideally you should be flushing the standard output as below:
printf("hello");
fflush(stdout);
fork();
I'm trying to do an assignment for one of my classes and no professors/fellow classmates are getting back to me. So before you answer, please don't give me any exact answers! Only explanations!
What I have to do is write a c program (timeout.c) that takes in two command line arguments, W and T, where W is the amount of time in seconds the child process should take before exiting, and T is the amount of time the parent process should wait for the child process, before killing the child process and printing out a "Time Out" message. Basically, if W > T, there should be a timeout. Otherwise, the child should finish its work and then no timeout message is printed.
What I wanted to do was just have the parent process sleep for T seconds, and then kill the child process and print out the timeout, however printing out the timeout message would happen no in both cases. How do I check to see that the child process is terminated? I was told to use alarm() for this, however I have no idea of what use that function would serve.
Here's my code in case anyone wants to take a look:
void handler (int sig) {
return;
}
int main(int argc, char* argv[]){
if (argc != 3) {
printf ("Please enter values W and T, where W\n");
printf ("is the number of seconds the child\n");
printf ("should do work for, and T is the number\n");
printf ("of seconds the parent process should wait.\n");
printf ("-------------------------------------------\n");
printf ("./executable <W> <T>\n");
}
pid_t pid;
unsigned int work_seconds = (unsigned int) atoi(argv[1]);
unsigned int wait_seconds = (unsigned int) atoi(argv[2]);
if ((pid = fork()) == 0) {
/* child code */
sleep(work_seconds);
printf("Child done.\n");
exit(0);
}
sleep(wait_seconds);
kill(pid, SIGKILL);
printf("Time out.");
exit(0);
}
Although waitpid would get you the return status of the child, its default usage would force parent to wait until the child terminates.
But your requirement (if i understood correctly) only wants parent to wait for a certain time, alarm() can be used to do that.
Then, you should use waitpid() with a specific option that returns immediately if the child has not exited yet (study the api's parameters). So if the child didn't exit, you could kill it, else you already receive its return status.
You want the timeout program to stop more or less as soon as the command finishes, so if you say timeout -t 1000 sleep 1 the protecting program stops after about 1 second, not after 1000 seconds.
The way to do that is to set an alarm of some sort — classically, with the alarm() system call and a signal handler for SIGALRM — and then have the main process execute wait() or waitpid() so that when the child dies, it wakes up and collects the corpse. If the parent process gets the alarm signal, it can print its message and send death threats of some sort to its child. It might be sensible to try SIGTERM and/or SIGHUP before resorting to SIGKILL; the SIGTERM and SIGHUP signals give the errant child a chance to clean up whereas SIGKILL does not.
If you know how to manage signals, you could catch SIGALRM and SIGCHLD in your parent process. SIGCHLD will be raised when the client terminates, and SIGALRM when the timer expires. If the first raised signal is SIGALRM, the timeout expired, otherwise, if the first SIGNAL that the parent catches is SIGCHLD, the child has stopped before the expiration of the timeout.
wait() or waitpid() would still be necessary to collect the terminated child.
Consider the code:
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
/* main --- do the work */
int main(int argc, char **argv)
{
pid_t child;
if ((child = fork()) < 0) {
fprintf(stderr, "%s: fork of child failed: %s\n",
argv[0], strerror(errno));
exit(1);
} else if (child == 0) {
// do something in child
}
} else {
// do something in parent
}
}
My question is from where does in the code the child process starts executing, i.e. which line is executed first??
If it executes the whole code, it will also create its own child process and thing will go on happening continuously which does not happen for sure!!!
If it starts after the fork() command, how does it goes in if statement at first??
It starts the execution of the child in the return of the fork function. Not in the start of the code. The fork returns the pid of the child in the parent process, and return 0 in the child process.
When you execute a fork() the thread is duplicated into memory.
So what effectively happens is that you will have two threads that executes the snippet you posted but their fork() return values will be different.
For the child thread fork() will return 0, so the other branch of the if won't be executed, same thing happens for the father thread.
When fork() is called the operating system assigns a new address space to the new thread that is going to spawn, then starts it, they will both share the same code segment but since the return value will be different they'll execute different parts of the code (if correctly split, like in your example)
The child starts by executing the next instruction (not line) after fork. So in your case it is the assignment of the fork's return value to the child variable.
Well, if i understand your question correctly, i can say to you that your code will run as a process already.When you run a code,it is already a process , so that this process goes if statement anyway. After fork(), you will have another process(child process).
In Unix, a process can create another process, that's why that happens.
Code execution in a child process starts from the next instruction following the fork() system call.
fork() system call just creates a seperate address space for the child process therefore it is a cloned copy of the parent process and the child process has all the memory elements of it's parent's process.
Thus, after spawning a child process through fork(), both processes (the parent process and the child process) resumes the execution right from the next instruction following the fork() system call.