Как работают fork и pid (if (pid! = 0)) в этом коде? - PullRequest
0 голосов
/ 25 декабря 2018
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int pid;
    int x, y;

    x = 10;
    y = 10;
    pid = fork();

    if (pid != 0)
    {
       x++;
       y--;
    }

    printf("x = %i y = %i\n", x, y);

    pid = fork();

    if (pid != 0)
    {
       x++;
       y--;
    }
    printf("x = %i y = %i\n", x, y);

    return (0);
}

Я полностью сбит с толку этой частью кода.Может кто-нибудь объяснить мне, как это работает?Также я не могу понять, какой процесс (дочерний / родительский) печатает.

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Функция fork() необычна;он возвращает два раза, по одному в каждом из двух разных (но тесно связанных) процессов, если это не сработает.Он возвращает -1, если это не удается (в исходном процессе, по необходимости).Если это успешно, он возвращает 0 в дочернем процессе, в то время как он возвращает PID дочернего процесса в исходном (родительском) процессе, который никогда не будет 0 (или отрицательным).

Вы должнынаучиться код инструмента.В контексте кода, использующего fork(), обычно эффективно напечатать PID (идентификатор процесса) и PPID (идентификатор родительского процесса), чтобы помочь выяснить, какой процесс печатает что.Короткий ответ на ваш вопрос о том, какой процесс печатает, состоит в том, что два процесса печатают данные из первого вызова printf(), а четыре процесса печатают данные из второго вызова printf() - если вы не передадите выходные данные программы другому (например cat), в этом случае кажется, что некоторые процессы печатают данные несколько раз.(См. Также printf() аномалия после fork().)

Давайте обработаем ваш код:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    printf("PID = %d\n", (int)getpid());

    int x = 10;
    int y = 10;

    int pid = fork();
    if (pid != 0)
    {
       x++;
       y--;
    }
    printf("1: x = %i y = %i (PID %d, PPID %d)\n",
           x, y, (int)getpid(), (int)getppid());

    pid = fork();
    if (pid != 0)
    {
       x++;
       y--;
    }
    printf("2: x = %i y = %i (PID %d, PPID %d)\n",
           x, y, (int)getpid(), (int)getppid());

    int status;
    int corpse;
    while ((corpse = wait(&status)) > 0)
    {
        printf("%d: child %d exited with status 0x%.4X\n",
               (int)getpid(), corpse, status);
    }

    return (getpid() % 16);
}

Оператор return в конце main() возвращаетненулевой статус выхода 15 раз из 16, просто чтобы сделать вещи немного интереснее.

Примеры запусков (программы ./fork43, построенной из fork43.c) - один без трубопровода, другой с трубопроводами:

$ ./fork43
PID = 26226
1: x = 11 y = 9 (PID 26226, PPID 23612)
2: x = 12 y = 8 (PID 26226, PPID 23612)
1: x = 10 y = 10 (PID 26227, PPID 26226)
2: x = 11 y = 9 (PID 26228, PPID 26226)
2: x = 11 y = 9 (PID 26227, PPID 26226)
26226: child 26228 exited with status 0x0400
2: x = 10 y = 10 (PID 26229, PPID 26227)
26227: child 26229 exited with status 0x0500
26226: child 26227 exited with status 0x0300
$ ./fork43 | cat
PID = 26230
1: x = 11 y = 9 (PID 26230, PPID 23612)
2: x = 11 y = 9 (PID 26233, PPID 26230)
PID = 26230
1: x = 10 y = 10 (PID 26232, PPID 26230)
2: x = 10 y = 10 (PID 26234, PPID 26232)
PID = 26230
1: x = 10 y = 10 (PID 26232, PPID 26230)
2: x = 11 y = 9 (PID 26232, PPID 26230)
26232: child 26234 exited with status 0x0A00
PID = 26230
1: x = 11 y = 9 (PID 26230, PPID 23612)
2: x = 12 y = 8 (PID 26230, PPID 23612)
26230: child 26233 exited with status 0x0900
26230: child 26232 exited with status 0x0800
$

При первом запуске исходный (родительский) процесс имеет PID 26226. Он разветвляется, а его дочерний - 26227. Родительскому процессу сообщается его дочерний PID, поэтому он увеличивает x и уменьшает * 1029.*;затем он выполняет оператор printf(), где строка формата начинается с 1:, печатая значения x как 11 и y как 9. В этом запуске родительский процесс снова разветвляется, создавая своего второго дочернего элемента с PID 26228.родительский элемент увеличивает x и уменьшает y снова и выполняет оператор printf(), где строка формата начинается 2:, прежде чем что-либо еще произойдет.Затем он достигает цикла wait() и ожидает смерти одного из его дочерних элементов.

Затем первый дочерний процесс (26227) выполняет инструкцию printf(), где строка формата начинается с 1:, но значенияx и y оба неизменны на 10. Затем он достигает второго разветвления и создает свой собственный дочерний процесс (внука исходного процесса) с PID 26229.

Второй дочерний элемент 26228 имеет (x,y) значения (11, 9), потому что это были значения, когда он был разветвлен, поэтому он печатает эти значения при выполнении оператора printf(), где строка формата начинается с 2:.

после первогодочерние вилки, ему сообщают PID своего дочернего элемента, поэтому он увеличивает x и уменьшает y, печатая значения 11 и 9.

Второй дочерний элемент завершается, и его статус сообщается исходным процессом.Процесс внука теперь выполняет оператор printf(), где строка формата начинается с 2:1. Since the value in pid was 0 twice, the values in x and y`, все еще неизменными на 10. Затем он завершается.

Первый дочерний элемент может сообщитьчто его ребенок вышел, а потом сам вышел.Родительский процесс сообщает, что первый дочерний элемент завершил работу и также завершил работу.

В целом имеется одна копия вывода PID, две копии 1: и 4 копии 2: (плюс три 'дочерние выходы 'отчеты).

Второй запуск с выводом по конвейеру на cat показывает, что выходные данные полностью буферизуются, а не буферизируются строкой, поэтому процессы сбрасывают записанные данные при выходе, а не при переводе строкнапечатаны.Вот почему существует 4 копии вводного вывода PID = 26230, а также 4 копии вывода 1:.До сих пор есть только 3 отчета о «выходе ребенка».

Печать информации о PID, как это, является ценным помощником в понимании кода.Важно признать, что последовательность вывода не является фиксированной.Разные прогоны могут создавать разные последовательности (совершенно отдельно от разных номеров PID) просто из-за алгоритма планирования и того, что еще происходит на компьютере одновременно.

0 голосов
/ 25 декабря 2018

Здесь

 pid = fork();

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

if (pid != 0) { } /* 2345 != 0 i.e parent process, lets assume pid returned is 2345 */

становится истинным, то есть родительским процессом, а затем возвращает 0 дочернему процессу с, так что в следующем случае он выглядит как

if (pid != 0) { /* 0 != 0 .. child process */ } 

ИзСтраница справочника fork ()

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ При успешном выполнении PID дочернего процесса возвращается в родительском 0 возвращается у ребенка .В случае ошибки -1 возвращается в родительский, дочерний процесс не создается, и errno устанавливается соответствующим образом.

Также fork() тип возвращаемого значения должен быть pid_t, а не int.,правильный

 pid_t pid = fork();
...