LINUX.ORG.RU

Странный fork()

 


0

1

Сегодня меня озадачили проблемой, которой не смог найти объяснение. Итак, имею следующий код:

#include <stdio.h>
#include <unistd.h>
void f(){
    puts("fork");
    fork();
}
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<2; i++ ){
        f();
        puts(".");
    }
}

при исполнении кода ожидаю увидеть 3 форка и 6 точек, что собственно и имею:

fork
.
fork
.
fork
.
.
.
.
но при замене puts на printf получаю вот такой результат:
fork.fork.fork.fork.fork.fork.fork.fork.
Как можно такое поведение объяснить при замене одной функции вывода на другую?

gcc 4.6.1

Отсутствием символов '\n' в конце строк в printf?

puts сам ставит эти символы.

DeVliegendeHollander ★★
()

for( i=0; i<2; i++ )
ожидаю увидеть 3 форка и 6 точек

??

anonymous
()

Да нормально все:

#include <stdio.h>
#include <unistd.h>
void f(){
    printf("fork");
    fork();
}
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<2; i++ ){
        f();
        printf(".\n");
    }
}

gcc 1.c && ./a.out 
fork.
fork.
fork.
fork.
fork.
fork.

Вот так красивше:

#include <stdio.h>
#include <unistd.h>
pid_t FORK_PID;
void f(){
    printf("fork");
    FORK_PID = fork();
}
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<3; i++ ){
        f();
        printf(", PID=%d\n", FORK_PID);
    }
}

gcc 1.c && ./a.out 
fork, PID=24489
fork, PID=0
fork, PID=24490
fork, PID=0
fork, PID=24491
fork, PID=0
fork, PID=0
fork, PID=24492
fork, PID=24494
fork, PID=0
fork, PID=0
fork, PID=24493
fork, PID=0
fork, PID=24495

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Вот так еще понятней:

#include <stdio.h>
#include <unistd.h>
pid_t FORK_PID;
void f(){
    printf("fork");
    FORK_PID = fork();
}
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<3; i++ ){
        f();
        printf(", i=%d, PID=%d\n", i, FORK_PID);
    }
}

gcc 1.c && ./a.out 
fork, i=0, PID=24571
fork, i=0, PID=0
fork, i=1, PID=24572
fork, i=1, PID=0
fork, i=1, PID=24573
fork, i=1, PID=0
fork, i=2, PID=24574
fork, i=2, PID=0
fork, i=2, PID=24575
fork, i=2, PID=24577
fork, i=2, PID=0
fork, i=2, PID=0
fork, i=2, PID=24576
fork, i=2, PID=0

Eddy_Em ☆☆☆☆☆
()

похоже меня неправильно поняли, я знаю, чем отличаются puts и printf, меня смущает то, что их заимная замена не должна приводить к увеличению\уменьшению копий процессов, которые порождает fork

EugeneBas ★★
() автор топика
Ответ на: комментарий от EugeneBas

все-таки дело в буферизации, т.к. такой код

#include <stdio.h>
#include <unistd.h>
void f(){
    fprintf(stderr, "fork");
    fork();
}
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<2; i++ ){
        f();
        fprintf(stderr, ".");
    }   
}

выводит

fork.fork.fork....

stderr, в отличие от stdout не буферизован, если заменить stderr на stdout, то получится то же, что и в начальном посте с printf.

hatefu1_dead
()
Ответ на: комментарий от AptGet

спасибо всем, теперь все понятно, проблема решена

EugeneBas ★★
() автор топика
Ответ на: комментарий от hatefu1_dead

так почему же все таки 6 точек? и почему i не меняется? она же должна измениться и в дочернем процессе?

anonymous
()
Ответ на: комментарий от anonymous

оригинальный код:

#include <stdio.h>
int main ( int argc, char ** argv ){
    int i;
    for( i=0; i<2; i++ ){
        fork();
        printf(".");
    }
    return 0;
}
при его исполнении вызывается 6 раз printf из 4 приложений (1 родительское и 3 дочерних), 6 раз как раз потому, что i увеличивается

но такой код выведет 8 точек, как объяснили выше, это связано с тем, что дочерние процессы унаследуют не только значение i из родительского процесса, но и еще буфер вывода в стандартный поток, который очистится только при завершении процесса, т.к. никто не вызывает ни flush, ни пишет «\n» в поток, что очищает буфер и выводит все в консоль

надеюсь, что понятно объяснил

EugeneBas ★★
() автор топика
Ответ на: комментарий от EugeneBas

спасибо, только наверное 2 дочерних процесса. не понятно, что после первого прохода цикла i должна стать равной двойке?!

anonymous
()
Ответ на: комментарий от anonymous

3 дочерних - первый дочерний, когда i = 0, порождает еще один дочерний процесс. после первого прохода цикла i становится равной 1.

hatefu1_dead
()
Ответ на: комментарий от anonymous

по порядку:

i=0;
fork() - получаем 2 процесса с i=0;
каждый из них делает printf(".")

i=1;
оба процесса, которые мы получили на предыдущей итерации опять вызывают fork()
в итоге имеем 4 процесса с i=1;
каждый из них опять вызывает printf(".")

i=2;
все 4 процесса выходят из цикла и завершаются      

в итоге получается, что имеели 4 процесса, которые суммарно вызвали 6 раз printf

EugeneBas ★★
() автор топика
Ответ на: комментарий от EugeneBas

спасибо, разобрался. а на каком уровне буфер для ввода-вывода копируется? всегда считал, что этот буфер зарыт в glibc, а не в ядре. где в структуре struct_task храниться указатель на этот буфер ввода-вывода?

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.