Reputation: 1
I am new to programming processes and my basic program doesn't really work as I expected. I am running this code on Ubuntu 18.04 on a Oracle VM.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("--beginning of program\n");
int counter = 0;
pid_t pid = fork();
if (pid == 0)
{
// child process
int i = 0;
for (; i < 5; ++i)
{
printf("child process: counter=%d\n", ++counter);
}
}
else if (pid > 0)
{
// parent process
int j = 0;
for (; j < 5; ++j)
{
printf("parent process: counter=%d\n", ++counter);
}
}
else
{
// fork failed
printf("fork() failed!\n");
return 1;
}
printf("--end of program--\n");
return 0;
}
Here is the result I always get:
--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
parent process: counter=4
parent process: counter=5
--end of program--
--beginning of program
child process: counter=1
child process: counter=2
child process: counter=3
child process: counter=4
child process: counter=5
--end of program--
Here is my command to compile the program:
gcc main.c -o main
Thank you!
Upvotes: 0
Views: 587
Reputation: 164679
Printing 5 strings happens too fast, the parent process completes its loop before the child process has begun its own. Try more loops, 500 Works For Me™.
Note that the parent and child do not share memory. The child will inherit counter = 0
but does not share counter
with its parent. They will both count independently. Coordinating processes requires more advanced techniques.
Other issues.
You're getting --end of program--
twice because the child process does not exit. Once it's done with its loop it continues running the rest of the code. Add an exit(0)
to the child.
If you want to declare the "end" after the child is done, use wait
to wait for your child process to complete.
waitpid(pid, NULL, 0);
printf("--end of program--\n");
You can get --beginning of program
twice if the output is to a pipe or file, like ./program | cat
or ./program > output
. Because of I/O buffering.
Writing to disk is slow. Rather than writing everything immediately as soon as its printed, it is written to memory and then written to disk. There's three common types of buffering: unbuffered, line buffered, and block buffered. Which kind of buffering depends on what you're writing to.
Unbuffered is just what it says, you call printf
and it is sent. stderr
is usually unbuffered because it's important to see errors as they happen.
Line buffered stores the output in memory until it sees a newline, then it sends the whole line. Sending it known as "flushing the buffer". stdout
is usually line buffered. This is a throwback to when terminals were literally printing a line on paper.
This can lead to strange results.
fprintf(stdout, "First");
fprintf(stderr, "Second");
fprintf(stdout, "Third\n");
Because stdout
is line buffer the result will be SecondFirstThird
.
Unless stdout
or stderr
are not going to a terminal. If they're going to a pipe or a file, they're probably block buffered. This means output will be buffered until a certain amount of data is seen, then it will be flushed.
In your code, if stdout
is line buffered printf("--beginning of program\n");
is flushed immediately. But if stdout
is redirected to a file it is block buffered and does not write immediately. "--beginning of program\n"
is still in stdout
's buffer. When you fork, the child gets a copy of that buffer and adds to it. So both the child and parent print "--beginning of program\n"
.
You can cure this by explicitly flushing your stdout buffer before forking using fflush
.
printf("--beginning of program\n");
fflush(stdout);
Upvotes: 2
Reputation:
The output you get will vary from machine to machine with the current code you have. For example when I ran the code the process scheduler decided to run the the parent process then the child and back to the parent and back and forth until they both finished.
See the image attached.
https://i.sstatic.net/a9mdt.jpg
in your case however, the process scheduler ran the parent first and finished, then it ran the child and finished.
If you wanted the child to run first then the parent we could use the wait(&status) in the parent to ensure that the child runs first. See code below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
printf("--beginning of program\n");
int counter = 0;
int wait3, status;
pid_t pid = fork();
if (pid == 0)
{
// child process
int i = 0;
for (; i < 5; ++i)
{
printf("child process: counter=%d\n", ++counter);
}
}
else if (pid > 0)
{
wait3 = wait(&status);
// parent process
int j = 0;
for (; j < 5; ++j)
{
printf("parent process: counter=%d\n", ++counter);
}
}
else
{
// fork failed
printf("fork() failed!\n");
return 1;
}
printf("--end of program--\n");
return 0;
}
Upvotes: 0