как проверить, если стандартный вывод закрыт - PullRequest
6 голосов
/ 16 ноября 2011

Я получил некоторый код, который печатает на стандартный вывод, в псевдокоде это выглядит как

int main(){
    //allocate data
    while(conditional){
      char *string = makedata();
      fprintf(stdout,"%s",string);
    }
    //cleanup 
}

Это работает нормально, если условие переключено на ноль, но если я передам вывод как

./a.out |head -n10 >dumped

Тогда код никогда не достигает части очистки, я не понимаю, как проверить, закрывается ли стандартный вывод.

Спасибо

Ответы [ 4 ]

5 голосов
/ 16 ноября 2011

Ваш стандартный вывод не был закрыт, поэтому проверка на это будет бесполезной.Ваша программа получила SIGPIPE и завершена.SIGPIPE доставляется всякий раз, когда ваша программа пишет в канал, на котором нет читателей.В вашем примере это происходит, когда head выходит, закрывая его стандартный ввод.

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

(void)signal(SIGPIPE, SIG_IGN);

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

./a.out | ( head -n10 >dumped ; cat > /dev/null )

1 : пример оболочки действителен для bash, возможно, не для csh.

3 голосов
/ 16 ноября 2011

Он закрывается, завершив процесс с помощью SIGPIPE.

Если вы хотите продолжить, когда ваш вывод игнорируется, тогда установите обработчик SIG_IGN для SIGPIPE и обработайтеошибка от fprintf (которая будет отложена из-за буферизации, поэтому вы не можете предполагать, что записанные данные действительно достигли пользователя).

1 голос
/ 16 ноября 2011

Как Роб указывает в комментариях к своему ответу, вы не беспокоитесь о том, что стандартный вывод закрыт; скорее, вы обеспокоены тем, что другой конец трубы закрыт. Это может быть педантизм, но это приводит к решению вашей проблемы. А именно, вам не важно, закрыт ли stdout, но только если ваш printf завершится успешно. Вам следует проверить возвращаемое значение printf: если оно равно -1, запись не удалась.

Как указывает Саймон Рихтер, вы никогда не получите возвращаемое значение printf, если не игнорируете SIGPIPE, потому что результатом записи в стандартный вывод, когда другая сторона канала закрыта, является то, что SIG_PIPE будет отправлено на процесс. Так что вам нужно сделать что-то вроде:

  signal( SIGPIPE, SIG_IGN ); /* Careful: you now must check the return of *all* writes */
  if( fprintf( stdout, ... ) == -1 ) {
    /* handle the error */
  }
0 голосов
/ 16 ноября 2011

Я не пробовал этого, но при условии, что вы использовали стандартный файловый дескриптор для stdout, вы можете попытаться выполнить fstat (1, & stat_structure) и проверить коды возврата и ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...