После того, как fork (), где ребенок начинает его выполнение?

22

Я пытаюсь изучить программирование в UNIX и натолкнулся на вопрос относительно fork (). Я понимаю, что fork () создает идентичный процесс текущего запущенного процесса, но где он начинается? Например, если у меня есть код

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");
    fflush (stdout);
    retval = fork ();
    printf ("Which process printed this?\n");

    return (EXIT_SUCCESS);
}

Выход:

Это определенно родительский процесс.
Какой процесс напечатал это?
Какой процесс напечатал это?

Я думал, что это fork()создает тот же процесс, поэтому я изначально, что в этой программе, fork()вызов будет рекурсивно вызываться навсегда. Я думаю, что новый процесс, созданный из fork()запускается после fork()вызова?

Если я добавлю следующий код, чтобы различать родительский и дочерний процессы,

if (child_pid = fork ()) printf ("This is the parent, child pid is %d\n", child_pid);
else printf ("This is the child, pid is %d\n",getpid ());

после вызова fork (), где дочерний процесс начинает свое выполнение?

Жиль "ТАК - перестань быть злым"
источник
5
man forkдостаточно уверен, чтобы ответить на ваш вопрос, кстати
Алекс

Ответы:

23

Новый процесс будет создан в рамках fork()вызова и начнется с возврата из него, как родительский. Возвращаемое значение (в котором вы сохранили retval) fork()будет:

  • 0 в дочернем процессе
  • PID ребенка в родительском процессе
  • -1 в родителе, если произошел сбой (нет ребенка, естественно)

Ваш тестовый код работает правильно; он сохраняет возвращаемое значение из fork()in child_pidи использует ifдля проверки, равен ли он 0 или нет (хотя он не проверяет наличие ошибки)

Михаил Мрозек
источник
13

Я думал, что fork () создает тот же процесс, поэтому я изначально думал, что в этой программе вызов fork () будет рекурсивно вызываться вечно. Я думаю, что новый процесс, созданный из fork (), запускается после вызова fork ()?

Да. Давайте нумеруем строки:

int main (int argc, char **argv)
{
    int retval;                                               /* 1 */
    printf ("This is most definitely the parent process\n");  /* 2 */
    fflush (stdout);                                          /* 3 */
    retval = fork ();                                         /* 4 */
    printf ("Which process printed this?\n");                 /* 5 */
    return (EXIT_SUCCESS);                                    /* 6 */
}

Поток выполнения:

caller process     fork()  ...
                          
original program            exec()  2  3  4  5  6
                                               
forked program                                   5  6

... который объясняет именно то, что вы получили.

Если вы хотите узнать, как оригинальная и разветвленная программа могут вести себя по-разному, поскольку они обязательно используют один и тот же код, см . Ответ Михаила Мрозека.

badp
источник
Обратите внимание, что 1 на самом деле не инструкция. Также обратите внимание, что исходная и разветвленная программы на самом деле не работают одновременно - одна из них должна будет ждать, пока другая не завершится.
badp
1
В системах с несколькими ядрами и несколькими процессорами обе программы могут работать одновременно.
Jlliagre
@jilliagre Многоядерные системы - это многопоточность. Что касается систем с несколькими процессорами, я не знаю, так ли это на практике. Я не эксперт в этой области - и это кажется маловероятным. Если мы согласимся, что ОС может запускать несколько процессов одновременно (тогда как она будет обрабатывать параллелизм?), К тому времени, когда исходная программа выполнит инструкцию 4 на ЦП, другие ЦП, вероятно, все равно будут заняты другими процессами.
badp
Я бы сказал, что это очень вероятный сценарий, особенно если учесть, что на шаге 5 происходит базовый системный вызов с некоторыми операциями ввода-вывода. Занятость всех процессоров на самом деле не является обычной ситуацией, поскольку центральный процессор редко является узким местом в современных машинах. Кажется, вы тоже путаете многопоточность и многоядерность.
Jlliagre
8
Могу ли я просто прокомментировать, что эти диагональные стрелки фантастические .
JBirch
0

Реальное решение этого

switch (fork()) {
    case -1 :
        fprintf (stderr, "fork failed (%s)\n", strerror(errno));
        break;
    case 0 :  // child process comes here
        break;
    default : // parent process
        break;
}

// all continue here
ott--
источник
-1

независимо от того, какой код следует сразу после fork(), копируется в дочерний процесс и не смешивает родительский и дочерний процессы, это две разные сущности, которые имеют одинаковую (дублированную, не разделяемую) среду.

Теперь посмотрим на ваш вывод ...

user2670535
источник