C-форк, имеющий дело с глобальной переменной - PullRequest
8 голосов
/ 29 января 2010

Я не понимаю вывод этой программы:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

int i = 0;

int main()
{
    while(i<3)
    {
        fork();

        printf("%d\n",i);
        ++i;
    }
}

Вывод:

0
1
2
2
1
2
0
1
2
2
2
1
2
2

Может кто-нибудь сказать мне, как я должен решить эту проблему, чтобы полностью понять, почему я получаю этот вывод?

Ответы [ 5 ]

25 голосов
/ 29 января 2010

Форк сделает копию процесса. Независимая копия процесса. Таким образом, если глобальная переменная содержит 3 во время разветвления, каждая копия процесса получает свои собственные 3. И если они изменяются, их модификации полностью независимы.

16 голосов
/ 29 января 2010

Измените свой код на это, и вывод должен иметь намного больше смысла:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int i = 0;

int main()
{
    while (i < 3)
    {
        fork();
        printf("pid = %d, i = %d\n", getpid(), i);
        ++i;
    }
    return 0;
}
5 голосов
/ 29 января 2010

Когда вы выполняете fork (), создается полная копия текущего процесса в его текущем состоянии. Это означает, что ваш начальный процесс создаст три новых процесса, которые находятся в середине цикла while, с i, соответственно, 0, 1 и 2 в каждом из них. Также будут напечатаны его собственные значения i.

Каждый из его дочерних элементов продолжит цикл после вызова fork(), распечатав его начальное значение i, увеличивая и зацикливая. Это означает, что потомки 0 будут печатать 0, 1 и 2 и порождать двух новых потомков с «начальными» значениями i 1 и 2. Потомки 1 выводят 1 и 2 и порождать еще одного потомка с "значение i из 2. Дети 2 напечатают 2 и выйдут из цикла.

Если вы продолжите это рассуждение, вы придете к выводу, что всего будет напечатано два 0, 4 1 и 8 2. Но, поскольку порядок выполнения зависит от того, как ОС планирует параллельные процессы, у вас не может быть гарантий на порядок печати. ​​

3 голосов
/ 29 января 2010

Попробуйте использовать pthreads, если вы хотите создать поток внутри процесса для параллельного программирования. Вам нужна функция pthread_create и pthread_join для последующей уборки.

Примерно так:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>


int i = 0;

void *threadFunc(void *arg) 
{
    printf("%d\n",i);
}

int main()
{
    int j = 0;  
    int returnValue = 0;
    pthread_t* myThread = (pthread_t*) calloc(3, sizeof(pthread_t));;

    while(i < 3)
    {

        returnValue = pthread_create(&myThread[i], NULL, threadFunc, NULL);
        printf("main thread: %d\n",i);
        i++;

    }


    for(j = 0; j < 3; j++)
    {
        pthread_join(myThread[j], NULL); 

    }

    return 0;
}

Но, возможно, нет, в зависимости от ваших реальных потребностей.

2 голосов
/ 29 января 2010

Это что-то вроде ...

 1 (main) instance, i = 0(unforked)
 fork() > 2 instances, with i's = 0(forked), and 0(forked)
0 output from main instance, increments its i, 2 instances with i = 1u, 0f
 main instance forks, there's 3 instances with i's 1f, 1f, 0f
1 output from main instance, increments its i, 3 instances with i = 2u, 1f, 0f
 main instance forks, there's 4 instances with i's 2f, 2f, 1f, 0f
2 output from main instance, increments its i, 4 instances with i = 3u, 2f, 1f, 0f
 main instance then dies, 3 instances with i = 2f, 1f, 0f
2 output from next instance, increments its i, 3 instances with i = 3u, 1f, 0f
 next instance then dies, 2 instances with i = 1f, 0f
1 output from next instance, increments its i to 2, 2 instances with i = 2u, 0f

... и т.д.

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

Как говорили другие люди, у каждого процесса есть свое собственное глобальное i, которое он отслеживает, и его значением является просто значение процесса разветвления i на развилке.

...