Можно ли определить порядок выполнения fork ()? - PullRequest
14 голосов
/ 14 июля 2011

Я работаю над упражнением по учебнику «Концепции операционной системы, 7-е издание», и меня немного смущает, как работает fork().Насколько я понимаю, fork() создает дочерний процесс, который выполняется одновременно с его родителем.Но тогда, как мы точно знаем, какой процесс запускается первым?Я имел в виду порядок выполнения.

Задача
Напишите программу на C, используя системный вызов fork(), который генерирует последовательность Фибоначчи в дочернем процессе.Номер последовательности будет указан в командной строке.

Это мое решение:

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

void display_fibonacci_sequence( int n ) {
    int i = 0;
    int a = 1;
    int b = 1;
    int value;
    printf( "%d, %d, ", a, b );
    for( ;i < n - 2; ++i ) {
        value = a + b;
        printf( "%d, ", value );
        a = b;
        b = value;
    }
    printf( "\n" );
}

int main( int argc, char** argv ) {
    int n;
    pid_t pid;
    pid = fork();
    if( argc != 2 ) {
        fprintf( stderr, "Invalid arguments" );
        exit( -1 );
    }
    n = atoi( argv[1] );

    if( pid < 0 ) {
        fprintf( stderr, "Fork failed" );
        exit( -1 );
    }
    else if( pid == 0 ) {
        display_fibonacci_sequence( n );
    }
    else { // parent process
        // what do we need to do here? 
    }
}

Если честно, я не вижу никакой разницы между использованием fork и не используя fork.Кроме того, если я хочу, чтобы процесс parent обрабатывал ввод от пользователя, и позволял процессу child обрабатывать отображение, как я могу это сделать?

Ответы [ 5 ]

14 голосов
/ 14 июля 2011

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

Первый вопрос

Если честно, я не вижу никакой разницы междуиспользуя fork и не используя fork.

Это потому, что пример не очень хороший.В вашем примере родитель ничего не делает, так что разветвление бесполезно.

Секунда

else {
    // what do we need to do here? 
}

Вам нужно wait (2) , чтобы дочерний процесс завершился,Убедитесь, что вы внимательно прочитали эту страницу.

Третий

Я хочу, чтобы родительский процесс обрабатывал ввод от пользователя, и чтобы дочерний процесс обрабатывал отображение

Прочитать ввод перед вилкой и «обработать» дисплей внутри if (pid == 0)

Четвертый

Но тогда как мы точно узнаем, какой процесс выполняется первым?

Очень немногие программы должны заниматься этим.Вы не можете знать порядок исполнения, он полностью зависит от среды.TLPI говорит следующее:

После fork () не определено, какой процесс - родительский или дочерний - имеет следующий доступ к ЦП.В многопроцессорной системе они оба могут одновременно получать доступ к ЦП.

Приложения, которые неявно или явно полагаются на определенную последовательность выполнения для достижения правильных результатов, открыты для отказа из-за условий гонки

Тем не менее, операционная система может позволить вам контролировать этот порядок.Например, Linux имеет /proc/sys/kernel/sched_child_runs_first.

9 голосов
/ 14 июля 2011

Мы не знаем, кто работает первым: родитель или ребенок.Вот почему родитель обычно должен ждать завершения дочернего процесса, если между ними есть некоторая зависимость от порядка выполнения.

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

Если вы хотите, чтобы родитель обрабатывал ввод, а потом ребенок вычислял, все, что вам нужно сделать, это переместить вызов на fork() ниже точки, в которойВы обрабатываете аргументы командной строки.Используя ту же базовую логику, что и выше, пусть дочерний вызов display_fibonacci_sequence, а родитель просто ждет

2 голосов
/ 14 июля 2011

Несмотря на то, что вы не можете контролировать, какой процесс (родительский или дочерний) запланирован первым после fork (на самом деле для SMP / многоядерный это может быть оба !), Существует много способов синхронизации этих двух процессов. имея один ожидание, пока другой не достигнет определенной точки, прежде чем он выполнит какие-либо нетривиальные операции. Один классический, чрезвычайно портативный метод заключается в следующем:

  1. До fork вызовите pipe, чтобы создать канал.
  2. Сразу после fork процесс, который хочет ждать, должен закрыть конец записи канала и вызвать read на конце чтения канала.
  3. Другой процесс должен немедленно закрыть конец чтения канала и дождаться закрытия конца записи канала, пока он не будет готов к запуску другого процесса. (read вернет 0 в другом процессе)
2 голосов
/ 14 июля 2011

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

1 голос
/ 14 июля 2011

Но тогда как мы точно знаем, какой процесс запускается первым?Я имел в виду порядок исполнения.

Нет гарантии, кто побежал первым.fork возвращает 0, если это ребенок, и pid ребенка, если это родитель.Теоретически они могут работать одновременно в многопроцессорной системе.Если вы действительно хотите определить, какой из них запускается первым, у вас может быть общая блокировка между двумя процессами.Можно сказать, что тот, кто первым получает замок, побежал первым.

С точки зрения того, что делать в вашем утверждении else.Вам нужно дождаться завершения дочернего процесса, используя wait или waitpid.

Если честно, я не вижу никакой разницы между использованием fork и не использованием fork.

Разница в том, что вы создаете дочерний процесс,Еще один процесс в системе, выполняющий вычисления.Для этой простой проблемы опыт конечного пользователя одинаков.Но fork сильно отличается, когда вы пишете системы, такие как серверы, которые должны работать с вещами одновременно.

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

У вас, похоже, уже есть эта настройка.Родительскому процессу просто нужно дождаться завершения дочернего процесса.Дочерний процесс printf выдаст результаты в терминал.И родительский процесс в настоящее время получает пользовательский ввод из командной строки.

...