вилка в цикле for

У меня есть сомнения в следующем фрагменте кода и его поведении:

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

#define N 5
#define nt 1

int pm[N][2],pid[N];
int i,j,size;
char s[100];
int count=0;

int main()
{
 for(i=1;i<N;i++)
    {
      printf("\n i=%d",i);

      if(pid[i]=fork() == -1)
        {
          printf("\n fork not wrking");
          exit(1);
        }
      else if(pid[i]>0)
        {
          printf(" \n pid:%3d\n",pid[i]);
        break;
        }

    }
return 0;
}

Сначала я думал, что код порождает процесс и пропускает цикл. Таким образом,
1 порождает 2 и пропускает.
2 порождает 3 и пропускает
3 порождает 4 и пропускает
4 порождает 5 и пропускает.

Я попытался выполнить этот код и был удивлен полученным ответом (для printf i в коде). Вот результат

 i=1
 i=2
 i=3
 i=2
 i=4
 i=3
 i=3
 i=3
 i=4
 i=4
 i=4
 i=4
 i=4
 i=4
 i=4

Может ли кто-нибудь объяснить мне, что здесь происходит. ПРИМЕЧАНИЕ. Я работаю на машине Solaris.


person tomkaith13    schedule 13.02.2010    source источник
comment
Можете ли вы опубликовать полный компилируемый код? Вы также должны закончить свою программу печатью новой строки.   -  person Alok Singhal    schedule 13.02.2010
comment
@Alok: я только что вставил весь код, который выполняю. Я делаю это на машине Solaris. Не уверен, что это актуально   -  person tomkaith13    schedule 13.02.2010
comment
Код, который вы только что вставили, немного отличается! Чуть-чуть, но по большому счету разные. ;-)   -  person John Kugelman    schedule 13.02.2010


Ответы (5)


Обновлять

В обновленном коде отсутствует набор скобок. Это должно быть if ((pid[i] = fork()) == -1), а не if (pid[i] = fork() == -1)!

Последний эквивалентен if (pid[i] = (fork() == -1)) из-за правил приоритета. Это заканчивается тем, что каждый раз в цикле присваивается 0 для pid[i], поэтому родители думают, что они являются дочерними процессами, и не выходят из цикла.


Я согласен с вашим анализом того, что должно произойти. Родитель должен породить дочерний элемент, а затем выйти, поэтому каждая распечатка i=n должна отображаться только один раз.

Вы уверены, что ввели его точно так, как указано в вашем вопросе? Я запустил вашу программу (с небольшими изменениями) и получил предсказанный вами результат:

$ cat fork.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define N 5

int main() {
    int pid[N], i;

    for(i=1;i<N;i++) /* What’s the total number of processes? */
    {
    printf("i=%d\n",i); // Output of all the is
    if((pid[i]=fork())==-1) exit(1);
    else if(pid[i] > 0) break;
    }

    return 0;
}
$ gcc -o fork fork.c
$ ./fork
i=1
i=2
$ i=3
i=4

Обратите внимание, что я переместил \n в распечатку в конец. Когда вы помещаете его в начало строки, вы получаете stdout, который не сбрасывается, поэтому вы получаете несколько распечаток, когда родительский и дочерний процессы очищают свои выходные буферы. Это может быть причиной вашей проблемы. FWIW на моем Mac я получил каждую распечатку дважды.

person John Kugelman    schedule 13.02.2010
comment
+1, а также ваши и мои правки в коде абсолютно одинаковы. :-) - person Alok Singhal; 13.02.2010
comment
@John: Спасибо за это последнее обновление. Теперь он работает нормально. Не могу поверить, что брекеты устроили такой беспорядок. Еще раз спасибо - person tomkaith13; 13.02.2010
comment
Хороший улов. Я думаю, что в исходном опубликованном коде был дополнительный набор скобок. - person Kevin Gale; 13.02.2010

Fork создает дублирующий процесс, содержащий все, что делает родительский процесс, включая дескрипторы файлов и т. д. Единственная разница заключается в возвращаемом значении fork(): родительский процесс видит pid, а дочерний — ноль.

Первая итерация создает первого потомка. Его копия i также равна 1, как и родитель. Ребенок вырывается из петли. Я получаю от вас разные результаты, когда запускаю его:

[wally@zf ~]$ ./a.out
i=1
i=2
i=3
i=4
person wallyk    schedule 13.02.2010

Какой вариант Unix вы используете. Есть ли шанс, что fork не вернет int?

В этом случае сравнение pid[i] > 0 может завершиться ошибкой.

person Kevin Gale    schedule 13.02.2010

Выражение

if (pid[i] = fork() == -1) {

не будет делать то, что вы ожидаете. Вы наверное хотели сказать

if ((pid[i] = fork()) == -1) {
person mob    schedule 13.02.2010

Каждый дочерний процесс продолжает цикл с текущим значением i при порождении. В результате первый процесс выводит i из 1, а затем порождает дочерний процесс. Затем оба этих процесса печатают i из 2 и порождают дочерний процесс, всего четыре процесса. Все четыре из них выводят i из 3, и каждый порождает новый процесс, и, наконец, все 8 процессов выводят значение 4.

EDIT: Извините, я пропустил часть, где родитель должен был выйти из цикла. Что касается того, почему этого не происходит, это может быть связано с тем, что PID хранится как целое число со знаком, но достаточно велико, чтобы передать максимальное значение со знаком, что делает его отрицательным. Будет ли работать, если вы сделаете эту замену?

else if(pid[i] > 0) break;

to

else if(pid[i] != 0) break;
person Josh Townzen    schedule 13.02.2010