Как синхронизировать процессы внутри цикла while в c

#c #linux #process #fork

#c #linux #процесс #форк

Вопрос:

Я сталкиваюсь с настоящей дилеммой:

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

 char* input = (char *)malloc(sizeof(char));
input = "CONTINUE";

while(strcmp(input, "EXIT") != 0 )
{
    printf("%s", "prompt: ");
    scanf("%s", input);

    if( strcmp(input, "test") == 0 )
    {
        pid_t childPid;
        switch(childPid = fork())
        {
            case -1:
                printf("%s", "Error");
                break;
            case 0:
                foo(input);
                break;
        }
    }
    else if(/.../)
    {
    }
    else
    {
        input = "EXIT";
    }

}

void foo(char* input)
{
   printf("%s %s", "printing" input);
}
  

Итак, проблема в том, что при выполнении цикла он выводит «приглашение: » в первый раз,
затем он снова выводит «prompt:», и, наконец, дочерний процесс из инструкции if печатает свои выходные данные.

Похоже, что дочерние процессы не синхронизированы или что-то в этом роде, и я не могу понять, из-за чего это дополнительное «приглашение:» печатается во второй раз. Это пример вывода:

 prompt: test                  //typed "test"
prompt:                       //Where is this comming from?
printing test
prompt:                       //new iteration of loop expecting input
  

Комментарии:

1. У вас тоже есть проблемы с переполнением буфера в вашем коде. Вы выделяете достаточно места для одного символа и ожидаете, что в него будут помещены строки из 4 букв. Не говоря уже о том, что scanf печально известен тем, что вызывает переполнение буфера.

2. @Tangrs для простоты примера я использовал scanf. Реальный код использует getline().

3. Однако проблема с переполнением буфера все еще существует. Прошло много времени.

Ответ №1:

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

Ваш код ничего не делает в родительском коде, когда он успешно порождает дочерний (fork возвращает число, большее 0, указывающее идентификатор дочернего процесса; этот возврат не обрабатывается вашим коммутатором). Таким образом, родительский сервер возвращается к началу цикла while и снова выводит «приглашение».

Дочерний элемент вызывает foo (fork возвращает 0), но после этого ваш код просто выполняет break из инструкции switch. После этого дочерний элемент следует точно такому же пути к коду, что и родительский, поэтому он также выводит «приглашение», а затем выполняет scanf .

Вероятно, вы хотите сделать что-то большее в этом направлении:

 childPid = fork();
if (childPid < 0)
{
    perror("fork()");
}
else if (childPid == 0)
{
    foo(input);
    exit(0); // terminate the child process
}
else
{
    waitpid(childPid, NULL, 0); // suspend the parent until the child exits
}
  

Поскольку вы printf подключаетесь к обоим процессам, вы, вероятно, захотите приостановить родительский до завершения дочернего процесса (используя waitpid ). В противном случае «приглашение», скорее всего, будет напечатано до вывода из foo() . На некоторых платформах распечатки могут выполняться одновременно, что приводит к смешанным символам или полностью искаженному выводу терминала.

Комментарии:

1. Спасибо! Я думал, что есть что-то вроде того, что могло бы это сделать. Я пытался использовать wait (3) в родительском, но это не сработало, так что … теперь я знаю, как это сделать правильно. Большое спасибо!