Advertisement

I have a fork() in my eye!

Started by March 28, 2007 09:07 AM
4 comments, last by Alaklin 17 years, 6 months ago
Okay guys, straight to the topic: #include <stdio.h> int main() { printf("la"); fork(); printf("e"); return 0; } will unexpectedly produce the following output: laelae whilst the following code: #include <stdio.h> int main() { printf("la\n"); fork(); printf("e\n"); return 0; } will produce the expected output: la e e What's happening? why doesn't the first program output: laee? P.S. (I'm a complete beginner) [Edited by - gpulove on March 28, 2007 9:33:25 AM]
The output that you see is totaly based on timing and is known as a Race Condition. The fork() command is used make a copy of the currently running program and run it on another thread. Remember that each line of c++ is not atomic but is split up into assembly lines by the compiler that could get interrupted anytime by a context switch. As the computer runs the two programs the following output could happen based on timing:

Process1 : "la"
Process1 : "e"
Process2 : "la"
Process2 : "e"

or

Process1 : "la" (the line rewinds but has not yet finished the newline)
Process2 : "la\n"
Process2 : "e" (the line has not either rewinded or moved to the newline)
Process1 : "\n" (finishes the newline)
Process1 : "e\n"
Process2 : "\n"
Advertisement
Quote: Original post by gpulove
What's happening? why doesn't the first program output: laee?


The C standard library provides buufered I/O on stdout by default. What that means in your case is that the buffer is copied through the fork and then flushed when the newline is inserted, or alternatively when the buffer is flushed when the stream is closed at program end.

--smw

Stephen M. Webb
Professional Free Software Developer

Okay, BUT
"The fork() command is used make a copy of the currently running program and run it on another thread."

Well, fork() will basically create a child of the current process and run in parallel. The thing is the execution for the child process continues from the place where fork() was called. To sum this up: fork() will return 2 values: the child's pid in the father process and 0 in the child process (signalling whether we're writing code for the child or for the father).

Now:
#include <stdio.h>
int main()
{
printf("la");
fork();
printf("e");
return 0;
}

EDIT:
We posted almost at the same time :)
Now I understand, thanks!
should produce:
la -> executed by the father
e -> executed by the father
e -> executed by the child

or

la -> executed by the father
e -> executed by the child
e -> executed by the father

I realized the problem: printf uses intermediary buffers to output to the screen whilst basic primitives like write and read don't:
switching from printf to write, seems to have solved the problem:

#include <stdio.h>
int main()
{
write(0, "la", 2);
fork();
write(0, "e", 1);
return 0;
}
The problem is that there are some buffers in memory. fork() is an operation which has an effect which is incompatible with many libraries. This includes some of the C library. For complete safety:

- Close all files before you fork()
- Any libraries which rely on file descriptors etc, should be reset after a fork, or ideally, not initialised until after fork()

Mark
I dont have any *nix boxes close by so I can't try this out myself, but this should do the trick:
#include <stdio.h>int main(){printf("la");//added this - it should flush the buffer to the screen.fflush(stdout);fork();printf("e");return 0;}

The problem is that when you send data to an output device it may not write out the data before the next command, instead it will buffer it until a certain size has been met. Some characters, such as '\n', will cause the buffer to flush, which is why your second code bit pushed out the expected results.

What happned in your first code snippet was that "la" went into the stdout buffer, fork() then created another instance of your app at the same point (with an exact copy of the stdout buffer, contents being "la"). Then each instance appended their own copy of the buffer with "e". When return 0; was reached the buffers got flushed.

This topic is closed to new replies.

Advertisement