L'arrière-plan important ici est qu'il stdout
est nécessaire que la norme mette en mémoire tampon la configuration par défaut.
Cela provoque un \n
vidage de la sortie.
Comme le deuxième exemple ne contient pas de nouvelle ligne, la sortie n'est pas vidée et, en tant que fork()
copie du processus entier, elle copie également l'état du stdout
tampon.
Maintenant, ces fork()
appels dans votre exemple créent 8 processus au total - tous avec une copie de l'état du stdout
tampon.
Par définition, tous ces processus appellent exit()
lors du retour depuis main()
et des exit()
appels fflush()
suivis par fclose()
sur tous les flux stdio actifs . Cela inclut stdout
et par conséquent, vous voyez le même contenu huit fois.
Il est recommandé d’appeler fflush()
tous les flux avec une sortie en attente avant d’appeler fork()
ou de laisser l’appel enfant appelé explicitement _exit()
qui ne fait que quitter le processus sans vider les flux stdio.
Notez que l'appel exec()
ne vide pas les tampons stdio. Vous pouvez donc ne pas vous soucier des tampons stdio si vous appelez (après l'appel fork()
) exec()
et si vous échouez _exit()
.
BTW: Pour comprendre ce que la mise en mémoire tampon incorrecte peut causer, voici un ancien bogue sous Linux qui a été récemment corrigé:
La norme nécessite de ne stderr
pas mettre la stderr
mémoire tampon par défaut, mais Linux l'a ignoré et a fait en sorte que la ligne soit tamponnée et (pire encore) complètement mise en mémoire tampon au cas où stderr serait redirigé via un tube. Les programmes écrits pour UNIX produisaient donc des données sans nouvelle ligne trop tard sous Linux.
Voir le commentaire ci-dessous, il semble être corrigé maintenant.
Voici ce que je fais pour contourner ce problème Linux:
/*
* Linux comes with a broken libc that makes "stderr" buffered even
* though POSIX requires "stderr" to be never "fully buffered".
* As a result, we would get garbled output once our fork()d child
* calls exit(). We work around the Linux bug by calling fflush()
* before fork()ing.
*/
fflush(stderr);
Ce code ne nuit pas aux autres plates-formes, car appeler fflush()
sur un flux qui vient d'être vidé est un noop.
./prog1 > prog1.out
) ou un tuyau (./prog1 | cat
). Préparez-vous à avoir l'esprit brisé. :-)