Після 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напевне, щоб відповісти на ваше запитання, btw
alex

Відповіді:


23

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

  • 0 у дочірньому процесі
  • ПІД дитини в батьківському процесі
  • -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

... що точно пояснює отриманий вами результат.

Якщо ви хочете знати, як оригінальна та роздрібнена програма може поводитися по-різному, оскільки вони обов'язково мають один і той же код, дивіться відповідь Майкла Мрозека.


Зауважте, що 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

-1

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

Тепер подивіться ваш результат ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.