Понимание порядка fork () в C - PullRequest
0 голосов
/ 11 декабря 2018

Итак, у меня есть эта программа, которую я пытаюсь понять, она из старого экзамена, но я просто не могу ее понять.Как узнать порядок вилок и как меняются переменные?

static int g = -1;

int main(int argc, char *argv[])
{
    int v = 0;
    pid_t p;

    while (v++ < 6)
        if ((p = fork()) < 0) {
            perror("fork error");
            return 1;
        } else if (p == 0) {
            v++;
            g--;
        } else {
            g++;
            v+=3;
        if (waitpid(p, NULL, 0) != p) {
            perror("waitpid error");
            return 1;
        }
    }
    printf("mypid = %d parentpid = %d p = %d v = %d g = %d\n",
    getpid(), getppid(), p, v, g);
    return 0;
}

Ответы [ 2 ]

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

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

Таким образом, когда вы входите в цикл, v увеличивается до 1, а затем вы переходите.В этот момент родительский процесс имеет g = -1, v = 1, p =, а новый дочерний процесс имеет g = -1, v = 1, p = 0.Затем родитель переходит в случай else, увеличивая g до 0 и v до 4, а затем ожидая завершения дочернего процесса, тогда как потомок переходит в "else if (p == 0)", увеличивает v до 2, уменьшает gдо -2, и снова обходит цикл.

Оттуда у вас, надеюсь, теперь есть достаточно информации, чтобы следовать логике, поскольку следующие два дочерних процесса отключаются, завершают цикл и печатают своисоответствующие результаты.Когда они это сделают, первый потомок также придет к концу своего waitpid с v = 6, выпадет из цикла и напечатает его результаты.

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

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

Вызов fork() одновременно запускает новый процесс и продолжает старый.Если есть какая-то ошибка, она возвращает значение ошибки.Все ошибки и только ошибки являются отрицательными числами.Это то, что проверяет первый блок if.

В новом процессе fork() возвращает 0. Ветвь, которая увеличивает v и уменьшает g, поэтому вызывается только в дочернем процессе, а неparent.

В исходном процессе функция fork() возвращает идентификатор процесса (PID) дочернего процесса, который является положительным целым числом.(Это будет позже передано waitpid(). Следовательно, ветвь, которая уменьшает v и увеличивает g, вызывается только в родительском процессе, а не в дочернем.

Каждый процесс имеет свою собственную копиюv и g. (Это основное различие между процессом и потоком: потоки разделяют память.) В современной операционной системе SMP происходит то, что дочерний процесс получает копию карты памяти родителя.они относятся к одним и тем же страницам физической памяти до тех пор, пока один или другой процесс не выполнит запись в них. Когда это происходит, создается копия этой страницы памяти, и оба процесса теперь получают свои собственные разные копии.

Так как современные ядра Linux реализуют fork(), дочерний процесс будет продолжаться раньше, чем родительский. Это существенно повлияло на производительность. Большинство программ, которые вызывают fork(), сразу же вызывают дочерний процесс exec() для запуска новой программы.означает, что ему вообще не понадобится копия родительской памяти (есть более новая, простаяТеперь можно запустить другую программу в новом процессе, posix_spawn().) С другой стороны, родительский процесс почти всегда продолжает работать и изменять свою память.Следовательно, предоставление ребенку возможности заявить, что он собирается отбросить память, которую он унаследовал, означает, что родителю не нужно беспокоиться о том, чтобы оставить неизмененную копию каких-либо страниц памяти для своих детей, и ядру не нужно проходить черезРигмарол копирования при записи.

На практике, однако, любой приличный компилятор будет хранить обе локальные переменные в регистрах, поэтому эта проблема не возникнет.

На следующей итерациицикл, который происходит только после завершения дочернего процесса, порождает новый дочерний процесс, используя обновленные значения родительских переменных.Каждый дочерний процесс также продолжает запускать цикл с теми же значениями v и g, которые он унаследовал от своего родителя.

...