I have been learning about fork in c and i have this program:
int main(void) {
int i;
printf("Start program\n");
printf("This is parent process %d: %d\n", getpid(), i);
int pid = fork();
printf("%d ", pid);
if(pid == 0) {
printf("This is process %d: %d\n", getpid(), i);
}
return 0;
}
This is the output:
Start program
This is parent process 4467: 0
4578 Start program
This is parent process 4467: 0
0 This is process 4578: 0
I do not understand why the parent code is called twice.
stdout is buffered. See e.g. setvbuf(3).
You forgot to call fflush(3) before doing your fork(2). As a rule of thumb, you'll better do fflush(NULL) before any fork().
That could explain the observed behavior (because flushing happens later in both parent and child processes, e.g. at program exit or return from main in crt0). You might (on Linux) use strace(1) to understand more exactly what is happenning.
BTW, fork(2) could fail. You should handle that (that is, handle the pid == -1 (or pid<0) case...).
Related
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/wait.h>
int main(){
int num = 2;
if (!fork()){
num++;
printf ("First: num = %d\n", num);
}else{
wait(NULL);
if (!fork()){
num++;
printf ("Second: num = %d\n", num);
}else{
wait(NULL);
num++;
printf ("Third: num = %d\n", num);
fflush(stdout);
exit(0);
}
}
fflush(stdout);
}
Can someone explain why num ends up being 3? I couldn't find a good explanation on fork().
What does (!fork()) even do??
fork is a Unix system call that duplicates a process. The program continues running twice, once in the parent process and once in a new child process. In the child process, fork returns zero, which is how the child can know it is the child. In the parent, it returns a process identification number for the child. (If an error occurs, it returns −1.)
This code:
if (!fork()){
num++;
printf ("First: num = %d\n", num);
says to create a child, then, in the child, increment num and print it. (In the child, fork returns zero, so !fork() is true.)
At this point, num is still 2 in the parent, because it was 2 when the fork was executed, and the num++ in the child incremented the child’s copy of it and did not affect the parent’s num.
In the else code:
wait(NULL);
if (!fork()){
num++;
printf ("Second: num = %d\n", num);
wait(NULL) says to wait for all children to finish execution, then create another child. That child does the same thing as above. Since it had 2 in num when it was created, the incremented produces 3, and the child prints 3.
The third piece of code does the same thing. The fflush calls are unnecessary.
Fork will create a new process based on the process you have created with your code. So when fork has created a new process it will return 0 for success.
And that is the reason for the output 3.
A detaied explanation how fork works can be found here: Fork-doc
I am writing this question with a bit of a confusion as i feel that I'm missing some point (that's why I am writing it, after all).
So i've been studying how multiple processes access a single file. I have a basic code that makes fork two times - both children fprintf into the same file, the main difference is that one of them sleeps and does much more fprintfs. Child exits when all fprinfs are done. At the same time the parent waitpids, and every time a child terminates it fprintfs into the same file.
What I wanted to see is 1) child process that had more fprintfs and sleep being terminated later then the other child (i think difference in running time should kinda provide a good probability that that would happen) - and that happens; 2) to see first fprintf of a parent process somewhere in the middle of the file as (how i thought!) the first child should be waitpided way before the second one is terminated - that is not what happened.
What happens every time is that both fprintfs are yielded into the file by the parent file at the very end of the file, just like the parent waited until both children are terminated and only then waitpided them.
Exchanging waitpid with wait obviously produced the same result.
I have several guesses:
The second child terminates faster then the parent have time to waitpid the first one and fprintf into the file.
The OS doesn't have time to send SIGCHILD to the parent before the second child terminates.
This is how waitpid works, like maybe signals are queued? (but i haven't found any specification of such functionality).
Could somebody please explain why I am not getting the message about first child terminating in the middle of the file, but do get it at the end?
The code of the program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#define N 1000000
#define SLEEP_TIME 20
int main(void)
{
FILE *fd1 = fopen("test.txt", "w");
pid_t pid1, pid2, cpid;
int wstatus;
pid1 = fork();
if(0 == pid1) {
for(int i = 0; i < N; ++i) {
fprintf(fd1, "child1 %d %d\n", getpid(), i);
}
sleep(SLEEP_TIME);
for(int i = 0; i < N; ++i) {
fprintf(fd1, "child1a %d %d\n", getpid(), i);
}
sleep(SLEEP_TIME);
fclose(fd1);
exit(EXIT_SUCCESS);
}
else if(-1 == pid1) {
exit(EXIT_FAILURE);
}
pid2 = fork();
if(0 == pid2) {
for(int i = 0; i < N/2; ++i) {
fprintf(fd1, "child2 %d %d\n", getpid(), i);
}
fclose(fd1);
exit(EXIT_SUCCESS);
}
else if(-1 == pid2) {
exit(EXIT_FAILURE);
}
while(((cpid = wait(&wstatus)) != -1)) {
//while(((cpid = waitpid(-1, &wstatus, WUNTRACED | WCONTINUED)) != -1)) if(WIFEXITED(wstatus))
fprintf(fd1, "child %d exited with status %d\n", cpid, wstatus);
}
if(errno == ECHILD) {
fprintf(fd1, "All children are waited for!\n");
}
else {
perror("waitpid");
exit(EXIT_FAILURE);
}
fclose(fd1);
exit(EXIT_SUCCESS);
}
The last lines of the resulting file:
2499998 child1a 7359 999997
2499999 child1a 7359 999998
2500000 child1a 7359 999999
2500001 child 7360 exited with status 0 //I wanted this one to be in the middle of the file!
2500002 child 7359 exited with status 0
2500003 All children are waited for!
No, waitpid does return each time a child exits. The problem is that your test is flawed.
On Unix, when you access regular files with stdio functions such as fprintf, by default they are fully buffered. This is desirable when only one process is writing to the file, as it reduces system call overhead, but can be undesirable when timing is important or when trying to synchronize with other processes.
So waitpid is in fact returning immediately after child2 exits, and fprintf is being called at that time, but it doesn't write its message into the the file immediately; rather, it remains buffered in the parent's memory. It will only be written out when the buffer fills up (doesn't happen in the parent, it's usually many KB), or when you call fflush (you don't), or when the file is closed (including on process exit). So both messages are written out together when you call fclose(fd1) in the parent, at which point both children have already exited.
For a test that better illustrates what's happening, disable buffering on this file by calling something like setvbuf(fd1, NULL, _IONBF, 0) immediately after opening the file. Then you should see the "child2 exited" message in the middle of the file, as you expect.
I have two code samples here
#include<stdio.h>
int main()
{
int i = 0;
i++;
fork();
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
return 0;
}
user#Ubuntu ~/Arena/c $ ./a
i - 1, pid - 6765, addr -0x7fffd892950c
i - 1, pid - 6766, addr -0x7fffd892950c
with my second program being
#include<stdio.h>
int main()
{
int i = 0;
i++;
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
fork();
return 0;
}
user#Ubuntu ~/Arena/c $ ./b
i - 1, pid - 6772, addr -0x7fff39120f2c
Well as far as I know fork should create a COMPLETE copy of the parent program from top to bottom and execute it, if it is that way why is the position of fork() call making such a big difference ? Could some one explain why is the printf omitted in my second program ?
fork() creates a copy of the process, and continues executing both processes at the point you call fork().
So in your second example, your printf is executed before the fork when there is only one process.
Fork creates a complete copy of your program but execution continues from the point in which fork is called. Put printf after the fork and see what happens.
Usually a fork call will be followed by a check if fork returned the pid of the child or not. If it did, then your current running process is the parent which received the child's pid in order to be able to manage the child, if it didn't then your current running process is the child.
For further enlightenment, try:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int i = 0;
i++;
printf("A: i - %d, pid - %d, addr -%p", i, getpid(), &i);
fork();
printf("\nB: i - %d, pid - %d, addr -%p\n", i, getpid(), &i);
return 0;
}
The first printf() doesn't include a newline, so the output is held in memory. The second printf() includes newlines, so the output appears after the program has forked. You should see the same information in the two lines tagged A; you should see different information in the two lines tagged B.
In a single-threaded application, the parent and child processes are almost identical except for the PID, Parent PID, and the value returned by fork(). For the full details, see the POSIX specification of fork().
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
void main()
{
int i = 1;
pid_t child_pid;
printf("The main program process ID is %d", (int) getpid());
printf("%d", i);
child_pid = fork();
if (child_pid != 0) {
i++;
printf("%d", i);
printf("This is the parent process, with ID %d \n", (int) getpid());
printf("The child process is %d ", (int) child_pid);
} else {
printf("%d", i);
printf("This is the child process, with ID %d \n", (int) getpid());
}
}
I'm running this program using the C language, using the fork() function. As I understand it, when a process calls fork(), a duplicate process, called a child process, is created.
The parent process continues executing from the point that fork() was called, and the child process, too, executes the same program from the same place.
So when I run my program, I expect the output be like the following text:
The main program process ID is 181411This is the child process, with ID 1815
The main program process ID is 18142This is the parent process,with ID 1814
The child process is 1815
But I actually see this output:
The main program process ID is 181411This is the child process, with ID 1815
The main program process ID is 181412This is the parent process,with ID 1814
The child process is 1815
It means that the child executes the program first!!!
When I put \n at the end of each printf statement the output is correct!!!
I've tried it on the Fedora v12 and rhel 5 distributions.
Is there any logical relation between the \n and the fork() operation? How I can solve this problem?
The problem is that output is line-buffered and it isn't really flushed to your screen until you either output \n or explicitly call fflush on stdout. (That said, there's no guarantee about which process is going to be faster at outputting stuff).
stdoutcommonly is line buffered. So the text to be printed is flushed to the console when receiving a '\n'.
Which process writes first is nondeterministicly handled by the OS.
To have things printed out without the need to have it triggered by '\n' using strerr is an option, as it normally is unbuffered.
My experience is that using stderr as fprintf(stderr,......) always appears to write unbuffered output. I was able to print the contents of a line before a segment error stopped execution. Try it again with stderr.
You can use:
setbuf(stdout, NULL)
to set the unbuffered output in stdout stream.
On success, the PID of the child
process is returned in the parent’s
thread of execution, and a 0 is
returned in the child’s thread of execution.
p = fork();
I'm confused at its manual page,is p equal to 0 or PID?
I'm not sure how the manual can be any clearer! fork() creates a new process, so you now have two identical processes. To distinguish between them, the return value of fork() differs. In the original process, you get the PID of the child process. In the child process, you get 0.
So a canonical use is as follows:
p = fork();
if (0 == p)
{
// We're the child process
}
else if (p > 0)
{
// We're the parent process
}
else
{
// We're the parent process, but child couldn't be created
}
p = fork();
/* assume no errors */
/* you now have two */
/* programs running */
--------------------
if (p > 0) { | if (p == 0) {
printf("parent\n"); | printf("child\n");
... | ...
Processes are structured in a directed tree where you only know your single-parent (getppid()). In short, fork() returns -1 on error like many other system functions, non-zero value is useful for initiator of the fork call (the parent) to know its new-child pid.
Nothing is as good as example:
/* fork/getpid test */
#include <sys/types.h>
#include <unistd.h> /* fork(), getpid() */
#include <stdio.h>
int main(int argc, char* argv[])
{
int pid;
printf("Entry point: my pid is %d, parent pid is %d\n",
getpid(), getppid());
pid = fork();
if (pid == 0) {
printf("Child: my pid is %d, parent pid is %d\n",
getpid(), getppid());
}
else if (pid > 0) {
printf("Parent: my pid is %d, parent pid is %d, my child pid is %d\n",
getpid(), getppid(), pid);
}
else {
printf("Parent: oops! can not create a child (my pid is %d)\n",
getpid());
}
return 0;
}
And the result (bash is pid 2249, in this case):
Entry point: my pid is 16051, parent pid is 2249
Parent: my pid is 16051, parent pid is 2249, my child pid is 16052
Child: my pid is 16052, parent pid is 16051
If you need to share some resources (files, parent pid, etc.) between parent and child, look at clone() (for GNU C library, and maybe others)
Once fork is executed, you have two processes. The call returns different values to each process.
If you do something like this
int f;
f = fork();
if (f == 0) {
printf("I am the child\n");
} else {
printf("I am the parent and the childs pid is %d\n",f);
}
You will see both the messages printed. They're being printed by two separate processes. This is they way you can differentiate between the two processes created.
This is the cool part. It's equal to BOTH.
Well, not really. But once fork returns, you now have two copies of your program running! Two processes. You can sort of think of them as alternate universes. In one, the return value is 0. In the other, it's the ID of the new process!
Usually you will have something like this:
p = fork();
if (p == 0){
printf("I am a child process!\n");
//Do child things
}
else {
printf("I am the parent process! Child is number %d\n", p);
//Do parenty things
}
In this case, both strings will get printed, but by different processes!
fork() is invoked in the parent process. Then a child process is spawned. By the time the child process spawns, fork() has finished its execution.
At this point, fork() is ready to return, but it returns a different value depending on whether it's in the parent or child. In the child process, it returns 0, and in the parent process/thread, it returns the child's process ID.
Fork creates a duplicate process and a new process context. When it returns a 0 value it means that a child process is running, but when it returns another value that means a parent process is running. We usually use wait statement so that a child process completes and parent process starts executing.
I think that it works like this:
when pid = fork(), the code should be executed two times, one is in current process, one is in child process.
So it explains why if/else both execute.
And the order is, first current process, and then execute the child.