Функциональность fork () - PullRequest
       14

Функциональность fork ()

2 голосов
/ 16 декабря 2010

Информация о системе: я использую 64-битную Ubuntu 10.10 на 2-месячном ноутбуке.

Привет всем, у меня есть вопрос о функции fork() в C. Из ресурсов, которые я использую (Stevens / Rago, YoLinux и Opengroup), я понимаю, что когда вы запускаете процесс, оба родитель и потомок продолжают выполнение следующей команды. Поскольку fork() возвращает 0 дочернему элементу, а идентификатор процесса дочернего элемента - родительскому, вы можете изменить их поведение с помощью двух операторов if, одного if(pid == 0) для дочернего элемента и if(pid > 0), предполагая, что вы разветвлены с помощью pid = fork().

Теперь у меня происходит самое странное. В начале своей основной функции я печатаю stdout пару аргументов командной строки, которые были назначены переменным. Это первый оператор без присваивания во всей программе, но кажется, что каждый раз, когда я вызываю fork позже в программе, эти операторы печати выполняются.

Цель моей программы - создать «дерево процессов», в котором каждый процесс имеет двух дочерних элементов, вплоть до глубины 3, создавая таким образом 15 дочерних элементов исходного исполняемого файла. Каждый процесс печатает идентификатор своего родительского процесса и идентификатор процесса до и после разветвления.

Мой код выглядит следующим образом и правильно прокомментирован, аргументы командной строки должны быть "ofile 3 2 -p" (я еще не дошел до реализации -p/-c flags):

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


int main (int argc, char *argv[])
{
    if(argc != 5)//checks for correct amount of arguments
    {
        return 0;
    }

    FILE * ofile;//file to write to
    pid_t pid = 1;//holds child process id
    int depth = atoi(argv[2]);//depth of the process tree
    int arity = atoi(argv[3]);//number of children each process should have

    printf("%d%d", depth, arity);

    ofile = fopen(argv[1], "w+");//opens specified file for writing



    int a = 0;//counter for arity
    int d = 0;//counter for depth
    while(a < arity && d < depth)//makes sure depth and arity are within limits, if the children reach too high(low?) of a depth, loop fails to execute
                                  //and if the process has forked arity times, then the loop fails to execute
    {
        fprintf(ofile, "before fork: parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent and self id to buffer
        pid = fork(); //forks program
        if(pid == 0)//executes for child
        {
            fprintf(ofile, "after fork (child):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
                    a=-1;//resets arity to 0 (after current iteration of loop is finished), so new process makes correct number of children
            d++;//increases depth counter for child and all of its children
        }
        if(pid > 0)//executes for parent process
        {
        waitpid(pid, NULL, 0);//waits on child to execute to print status
        fprintf(ofile, "after fork (parent):parent's pid: %d, current pid: %d\n", getppid(), getpid());//prints parent's id and self id to buffer
        }
        a++;//increments arity counter
    }


    fclose(ofile);
}

Когда я запускаю gcc main.c -o ptree, затем ptree ofile 3 2 -p, консоль рассылается спамом с "32", повторяющимся, по-видимому, бесконечно, и файл ofile имеет, казалось бы, правильный формат, но слишком большой для того, что, по моему мнению, должна делать моя программа делать

Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

6 голосов
/ 16 декабря 2010

Я не уверен, почему для детей будет выполняться от fputs до stdout, и у меня нет Unix-бокса для проверки / проверки.

Однако, следующее выпрыгивает:

int depth = *argv[2];//depth of the process tree
int arity = *argv[3];//number of children each process should have

Вы берете коды ASCII первого символа в argv[2] и argv[3] в качестве depth и arity, поэтому ваш код вместо этого пытается вызвать процессы 50^51из 2^3.

То, что вы хотите:

int depth = atoi(argv[2]);//depth of the process tree
int arity = atoi(argv[3]);//number of children each process should have

Как только вы исправите это, bleh[0] = depth и его близнец также нуждаются в исправлении.

edit Хотя сейчас это не проблема, вы довольно обрезаете длину некоторых вещей, которые вы sprintf вводите в obuf.Сделайте некоторые сообщения чуть длиннее и Kaboom! По крайней мере, вы захотите использовать snprintf или, еще лучше, fprintf непосредственно в файле.

edit Я только что понял, что fork, будучи функцией ОС, скорее всего, не знает о внутренней буферизации, выполняемой функциями CI / O.Это объясняет, почему вы получаете дубликаты (и родитель, и ребенок получают копию буферизованных данных в fork).Попробуйте fflush(stdout) перед циклом.Также fflush(ofile) перед каждым fork.

3 голосов
/ 16 декабря 2010

В вашем коде 2 ошибки:

1)

  int depth = *argv[2];//depth of the process tree
  int arity = *argv[3];//number of children each process should have

С этим кодом вы получаете первый символ из строк argv [2] и argv [3].Правильный код должен быть таким:

int depth = atoi(argv[2]);
int arity = atoi(argv[3]);

2)

bleh[0] = depth;
fputs(bleh, stdout);
bleh[0] = arity;
fputs(bleh, stdout);

Вы можете сделать что-то подобное bleh[0] = (char) depth;, но вы просто сохраните первый байт своего целого числа ине то, что вы хотите сделать, я думаю, если вы хотите напечатать целое число, просто используйте:

printf("%d\n%d", depth, arity);

Я просто попробовал ваш код с этими модификациями, и он, кажется, работает хорошо:)

Anhuin

0 голосов
/ 16 декабря 2010

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

Кроме того, кажется, что вы отправляете текст в файл, но все же он открывается в двоичном режиме, что кажется неправильным.

...