[comp.unix.wizards] Child doing parent's printf ??

satam@ecs.umass.edu (Kirtikumar Satam, ECE, UMASS Amherst) (02/12/90)

I was playing with fork() and wrote the following program. The program
works as expected when its stdout is tty. But, when I redirect it to
a file an additional printf comes. Here it is.
-----------------------------Child.c-------------------------
/*
 * This program demonstrates the use of fork() system call
 * to create child processes. It also shows the use of wait()
 * system call for process synchronization. Other than that the
 * the program is trivial.
 */

#include <stdio.h>
#include <sys/wait.h>

union wait *status_1; /* argument to wait()*/

int parent_pid, child_pid; /* pids of processes */ 
int got_child_pid; /* return values of wait() */
void main()
{
	parent_pid = getpid(); /* first get My pid */
	fprintf(stdout,"Parent : I am parent with pid %d\n",parent_pid); 
	if ((child_pid = fork()) == 0) /* enter child code */
	{
	   fprintf(stdout,"Child : I am child of parent %d and my pid is %d\n",
	   parent_pid, getpid());  
	   exit(0); /* exit with status 1 */
	} /* end child code */
	else if (child_pid != -1) 
	{
	   /* all set, then wait */
	   got_child_pid = wait(status_1); 
		/* get the pid from the dying child */
	   fprintf(stdout,"Parent : My child with pid %d died\n", 
		got_child_pid);
	   exit(0); /* exit with satisfaction */
	}
	/* fork() failed, so bye bye */
	perror("fork failed for child"); /* get the error */
	exit(1); /* exit with status 1 */
}
-----------------------------------------------------------------
Now, the output on tty is
----------------------tty output --------------------
Parent : I am parent with pid 7704
Child : I am child of parent 7704 and my pid is 7705
Parent : My child with pid 7705 died
----------------------------------------------------

ANd when I redirect it is
----------------------Redirected-------------------
Parent : I am parent with pid 7708
Child : I am child of parent 7708 and my pid is 7709
Parent : I am parent with pid 7708
Parent : My child with pid 7709 died
----------------------------------------------------

Clearly the third line is being printed by the child.
It can be construed that the string in the parent's virtual
space is being copied into the child's space before
it is removed from the system. This behaviour can be
attributed to slow tty rather than to a fast disk (here
actually disk buffers), but in reality it is the reverse.

The above problem can be removed by using fflush(stdout)
before forking. But, why it happens in the first place?

By the way, I am using ULTRIX-32 V3.1 (Rev. 9).

Any insight fellow wizards?
-satam
------------------------------------------------------------------------
Kirtikumar "Mumbaichaa" Satam
INTERNET : satam@ecs.umass.edu
BITNET : satam@umaecs.bitnet
217 Northwood Apts, Sunderland, MA 01375   Tel# 413-665-3222
------------------------------------------------------------------------

richard@aiai.ed.ac.uk (Richard Tobin) (02/14/90)

>I was playing with fork() and wrote the following program. The program
>works as expected when its stdout is tty. But, when I redirect it to
>a file an additional printf comes. Here it is.

Surprise!

When the output is a terminal, it is buffered in the program until a
linefeed is written.  Then it is flushed as if with fflush().

When the output is not to a terminal, it is buffered in the program until
"enough" has been written or until the program exits.  This is because it's
more efficient to do the actual writing in large blocks.  (If this was
done with terminal output, it would be rather confusing.)

When the program forks, the output is still buffered.  Both the child and
the parent get a copy of it, and both flush it when they exit.

>----------------------Redirected-------------------
>Parent : I am parent with pid 7708
>Child : I am child of parent 7708 and my pid is 7709
>Parent : I am parent with pid 7708
>Parent : My child with pid 7709 died
>----------------------------------------------------

>Clearly the third line is being printed by the child.

Actually, the first two lines are printed by the child when it exits,
and the third and fourth by the parent when it exits.

A solution is to flush all output streams before doing a fork().
An alternative if the child does no output is to have the child call
_exit() instead of exit(); this bypasses stdio cleanup.

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

hughes@silver.ucs.indiana.edu (larry hughes) (02/14/90)

If you flush the output and error channels before forking, your
problem should go away.

 //=========================================================================\\
||       Larry J. Hughes, Jr.        ||        hughes@ucs.indiana.edu        ||
||        Indiana University         ||                                      ||
||   University Computing Services   ||   "The person who knows everything   ||
||    750 N. State Road 46 Bypass    ||      has a lot to learn."            ||
||      Bloomington, IN  47405       ||                                      ||
||         (812) 855-9255            ||   Disclaimer: Same as my quote...    ||
 \\==========================================================================//

greyham@hades.OZ (Greyham Stoney) (02/22/90)

in article <9123.25d6719a@ecs.umass.edu>, satam@ecs.umass.edu (Kirtikumar Satam, ECE, UMASS Amherst) says:
> 
> I was playing with fork() and wrote the following program. The program
> works as expected when its stdout is tty. But, when I redirect it to
> a file an additional printf comes. Here it is.

How's this:
	standard output is line-buffered when the output is a terminal, but is
block buffered when the output is a file. Hence, when you run it from a
terminal, stdout is implicitly flushed at the end of each line, and you get
three messages. With output redirected though, the message is still in the
stdout buffer, and get duplicated by the fork. The child then adds it message
to the buffer, which eventually gets flushed at exit().

	Meanwhile, the parent adds its second message too, and they both get
flushed at exit(). Hence:

: Now, the output on tty is
: ----------------------tty output --------------------
: Parent : I am parent with pid 7704		<---- Flushed before the fork()
: Child : I am child of parent 7704 and my pid is 7705
: Parent : My child with pid 7705 died
: ----------------------------------------------------
: 
: ANd when I redirect it is
: ----------------------Redirected-------------------
: Parent : I am parent with pid 7708		<--- from child's buffer
: Child : I am child of parent 7708 and my pid is 7709
: Parent : I am parent with pid 7708		<--- from parent's buffer
: Parent : My child with pid 7709 died
: ----------------------------------------------------

> The above problem can be removed by using fflush(stdout)
> before forking.

Yep, that's your solution. Note that using stderr wont do it either cos it's
not buffered.

							Greyham.
-- 
/*  Greyham Stoney:                            Australia: (02) 428 6476  *
 *     greyham@hades.oz  - Ausonics Pty Ltd, Lane Cove, Sydney, Oz.      *
 * "Beware! Grid Bugs!"  \ Quotes from the Ultimate Video Experience...  *
 * "Nice Try, Timelord!" / Can you identify it? Win absolutely nothing!  */