Почему выходные данные простой программы на Си, добавляющие / удаляющие строки, непредсказуемо? - PullRequest
3 голосов
/ 28 июля 2011

Перво-наперво, я использую cygwin версии 1.7.1 на Windows 7. Код был скомпилирован с помощью gcc и запускался из командной строки bash. Здесь идет:

Я изучал, как работают fork () и exec (), поэтому я проверял википедию. Там я нашел следующий простой C-код для некоторого действия fork-on-fork:

#include <stdio.h>   /* printf, stderr, fprintf */
#include <unistd.h>  /* _exit, fork */
#include <stdlib.h>  /* exit */
#include <errno.h>   /* errno */

int main(void)
{
   pid_t  pid;

   /* Output from both the child and the parent process
    * will be written to the standard output,
    * as they both run at the same time.
    */

   pid = fork();
   if (pid == -1)
   {
      fprintf(stderr, "can't fork, error %d\n", errno);
      exit(EXIT_FAILURE);
   }

   if (pid == 0)
   {
      /* Child process:
       * When fork() returns 0, we are in
       * the child process.
       * Here we count up to ten, one each second.
       */
      int j = 0;
      for (j = 0; j < 10; j++)
      {
         printf("child: %d\n", j);
         sleep(1);
      }
      _exit(0);  /* Note that we do not use exit() */
   }
   else
   {
      /* Parent process:
       * When fork() returns a positive number, we are in the parent process
       * (the fork return value is the PID of the newly created child process).
       * Again we count up to ten.
       */

      int i = 0;
      for (i = 0; i < 10; i++)
      {
         printf("parent: %d\n", i);
         sleep(1);
      }
      exit(0);
   }
}

Теперь, когда я компилирую и запускаю его несколько раз, я, кажется, получаю непредсказуемое поведение ... иногда он работает как положено, иногда он включает в себя дополнительные символы новой строки в stdout, иногда он пропускает символы новой строки в std out. Вот пример вывода:

user@HAL10000 ~/c++/sandbox/src
$ gcc fork_and_stuff.c -o fork_and_stuff

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0child: 0
parent: 1child: 1
parent: 2child: 2

parent: 3child: 3
parent: 4child: 4
parent: 5child: 5

child: 6
parent: 6
child: 7
parent: 7
child: 8
parent: 8
child: 9
parent: 9

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0
child: 0
parent: 1
child: 1
parent: 2
child: 2
parent: 3
child: 3
parent: 4
child: 4
parent: 5
child: 5
parent: 6
child: 6
parent: 7
child: 7
parent: 8
child: 8
parent: 9
child: 9

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0child: 0

parent: 1child: 1

parent: 2child: 2

parent: 3child: 3

parent: 4child: 4

child: 5
parent: 5
parent: 6child: 6

parent: 7child: 7

child: 8parent: 8

parent: 9child: 9

Это какой-то жуткий вид выхода Мой компьютер часто посещается? Если да, то чем? И как я могу изгнать это?

Ответы [ 3 ]

3 голосов
/ 28 июля 2011

У меня такое ощущение, что это вызвано промывочным поведением. Попробуйте вызвать fflush(stdout); после каждого оператора печати и посмотрите, не изменит ли это результаты.

Для получения дополнительной информации я бы рекомендовал прочитать ответы на этот вопрос (особенно это объяснение поведения ISO для буферизованных и небуферизованных потоков ).

0 голосов
/ 28 июля 2011

Это нормальное поведение для fork (). Ваш код вызывает действительно приятное взаимодействие с планировщиком. Фактически это использовалось как низкокачественный ГСЧ.

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

Ваш код должен делать то, что вы хотите большую часть времени, если вы добавите usleep (500000); к вершине одной стороны; однако это поведение не должно зависеть от.

Цель fork () - создать два независимых процесса. Существуют стандартные механизмы блокировки межпроцессорной обработки, позволяющие вашему коду работать; однако их использование почти всегда является ошибкой. Существует стандартное правило UNIX: «Если программе нечего сказать, она ничего не должна сказать». Это позволяет им запускаться как фоновые процессы тривиально.

Кстати, вы настроили что-то очень похожее на трюк, который мы используем для демонстрации непредсказуемости планировщика.

0 голосов
/ 28 июля 2011

Здесь - это один из возможных способов изгнать злого духа, преследующего ваш компьютер :) То есть попробуйте запустить программу в оболочке Cygwin bash или в командной строке Windows. Проблема в том, что вывод не сбрасывается на \n. Чтобы сбросить его, попробуйте fflush(stdout) после каждого printf вызова.

...