OVH Cloud OVH Cloud

Croissance de fork()

5 réponses
Avatar
Damien Wyart
Bon, c'est un truc tout con et classique (quoique c'est plutôt le
forkbomb avec un while qui est souvent traité) puisque j'en ai déjà
entendu parler ici et là, mais je n'arrive pas à *vraiment* comprendre.

Avec un programme C de ce style (pas forcément ultra-respectueux des
normes, mais dans ce contexte, je pense que ça n'est pas gênant) :

int i, p;

int
main ()
{
for (i = 0; i < 2; i++)
{
p = fork ();
if (p == 0)
printf ("F%d ", i);
else
printf ("P%d ", i);
}
return 0;
}

j'obtiens 8 affichages alors que je m'attends à en avoir 6. Mon
raisonnement : au départ, un processus, i vaut 0. Après le fork, une
copie est créée, i y vaut également 0 ; chacun fait un affichage. Chaque
processus continue et passe au tour où i vaut 1. Chacun recrée une
copie, donc 4 processus en tout, et 4 affichages. Chacun s'arrête
ensuite puisque la boucle est finie. Donc pourquoi 8 affichages ? J'ai
l'impression que la boucle reprend à 0, mais dans ce cas, l'ensemble du
truc ne devrait jamais s'arrêter !

Idem avec i < 3, on obtient 24 affichages et non pas 14, bref il y a un
motif en n*2^n mais je n'arrive pas à le prouver rigoureusement puisque
je m'obstine à faire le somme des 2^i.


Merci pout tout éclaircissement...

--
DW

5 réponses

Avatar
Nicolas George
Damien Wyart wrote in message <43e79285$0$32151$:
Avec un programme C de ce style (pas forcément ultra-respectueux des
normes, mais dans ce contexte, je pense que ça n'est pas gênant) :

int i, p;

int
main ()
{
for (i = 0; i < 2; i++)
{
p = fork ();
if (p == 0)
printf ("F%d ", i);
else
printf ("P%d ", i);
}
return 0;
}


Ajoute un fflush(stdout); après les printf, à tout hasard.

Avatar
Pascal Bourguignon
Damien Wyart writes:

Bon, c'est un truc tout con et classique (quoique c'est plutôt le
forkbomb avec un while qui est souvent traité) puisque j'en ai déjà
entendu parler ici et là, mais je n'arrive pas à *vraiment* comprendre.

Avec un programme C de ce style (pas forcément ultra-respectueux des
normes, mais dans ce contexte, je pense que ça n'est pas gênant) :

int i, p;

int
main ()
{
for (i = 0; i < 2; i++)
{
p = fork ();
if (p == 0)
printf ("F%d ", i);
else
printf ("P%d ", i);
}
return 0;
}

j'obtiens 8 affichages alors que je m'attends à en avoir 6. Mon
raisonnement : au départ, un processus, i vaut 0. Après le fork, une
copie est créée, i y vaut également 0 ; chacun fait un affichage. Chaque
processus continue et passe au tour où i vaut 1. Chacun recrée une
copie, donc 4 processus en tout, et 4 affichages. Chacun s'arrête
ensuite puisque la boucle est finie. Donc pourquoi 8 affichages ? J'ai
l'impression que la boucle reprend à 0, mais dans ce cas, l'ensemble du
truc ne devrait jamais s'arrêter !

Idem avec i < 3, on obtient 24 affichages et non pas 14, bref il y a un
motif en n*2^n mais je n'arrive pas à le prouver rigoureusement puisque
je m'obstine à faire le somme des 2^i.


Merci pout tout éclaircissement...


J'obtiens le résultat attendu:

[ tmp]$ cat f.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main (void){
int i;
int p;
int level=0;
for(i=0;i<2;i++){
p=fork();
if(p==0){
level++;
printf("%*s child: i=%d, ppid=%d, pid=%d n",
level*3,"",i,getppid(),getpid());
fflush(stdout);}
else{
printf("%*s parent: i=%d, my pid=%d, forked child pid=%d n",
level*3,"",i,getpid(),p);
fflush(stdout);}}
return(0); }
[ tmp]$ gcc -o f f.c
-Wall -Werror -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align
-Wwrite-strings -Wconversion -Wstrict-prototypes -Wmissing-prototypes
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline
[ tmp]$ ./f
parent: i=0, my pid0814, forked child pid0815
parent: i=1, my pid0814, forked child pid0816
child: i=0, ppid0814, pid0815
parent: i=1, my pid0815, forked child pid0817
child: i=1, ppid0814, pid0816
child: i=1, ppid=1, pid0817
[ tmp]$
^^^^^^ Le processus 30816 doit s'être terminé avant
que le processus 30817 n'ait appelé getppid().

--
__Pascal Bourguignon__ http://www.informatimago.com/

"You can tell the Lisp programmers. They have pockets full of punch
cards with close parentheses on them." --> http://tinyurl.com/8ubpf

Avatar
Damien Wyart
* Nicolas George <nicolas$ in fr.comp.os.unix:
Ajoute un fflush(stdout); après les printf, à tout hasard.


En effet, c'est tout de suite mieux. Ca me rassure, mon raisonnement
était bon...

Donc c'est juste un effet de bord bizarre des E/S tamponnées ? Ca le
fait que sur Linux ou ?

--
DW

Avatar
Stephane Dupille
Donc c'est juste un effet de bord bizarre des E/S tamponnées ?


Oui.

Ca le fait que sur Linux ou ?


Non, ça existe sur plein de système et pas que des jeunes. Je me
souviens même d'un programme du genre :

int main (int argc, char **argv)
{
fork () ;
printf ("42n") ;
fork () ;
printf ("42n") ;
}

où le nombre de 42 n'est pas le même selon qu'on redirige stdout
vers un pipe ou un terminal (donc les appels "./a.out" et "./a.out |
more" ne donne pas la même chose). D'ailleurs, ça non-marche sur mon
BSD :

[gimli] ~/Temp> cat > test.c
int main (int argc, char **argv)
{
fork () ;
printf ("42n") ;
fork () ;
printf ("42n") ;
}
[gimli] ~/Temp> gcc test.c
[gimli] ~/Temp> ./a.out
42
42
42
42
42
42
[gimli] ~/Temp> ./a.out | more
42
42
42
42
42
42
42
42
[gimli] ~/Temp>


Rigolo, non ?

--
S> Je cherche aussi des adresses de lieux contenant des fossiles dans
S> la région parisienne
http://www.senat.fr/
-+- DP in <http://www.le-gnu.net> : La dianurette et les fossiles -+-

Avatar
DINH Viêt Hoà

où le nombre de 42 n'est pas le même selon qu'on redirige stdout
vers un pipe ou un terminal (donc les appels "./a.out" et "./a.out |
more" ne donne pas la même chose). D'ailleurs, ça non-marche sur mon
BSD :


vers un pipe, tu es en bufferisation avec flush après une certaine
taille de données.
vers un terminal, tu es en bufferisation avec flush à chaque saut de
ligne.

--
DINH V. Hoa,

"Et alors, les parents d'Odile ? Ils sont trop cool, et tout ce qu'ils
veulent, c'est qu'elle sorte en boîte tous le soirs [...]
et ils militent contre les maths à l'école ?" -- Virginie Despentes