Проблема с dup2, stdout и stderr - PullRequest
2 голосов
/ 19 октября 2010

Когда эта программа запущена, строка "stderr" отображается перед строкой "stdout".Зачем?Я думал, что dup2 заставит stderr и stdout использовать один и тот же файловый дескриптор, поэтому проблем с буферизацией не должно быть.Я использую gcc 3.4.6 на Solaris 10.

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

int main()
{
    int fd[2];
    int pid;
    char buf[256];
    int n;

    if(pipe(fd) < 0) {
        perror("pipe");
        return 1;
    }
    if((pid = fork()) < 0) {
        perror("fork");
        return 1;
    }
    else if(pid > 0) { // parent
        close(fd[1]);
        if((n = read(fd[0], buf, sizeof(buf))) > 0) {
            buf[n] = 0;
            printf("%s", buf);
        }
    }
    else {
        dup2(fd[1], fileno(stdout));
        dup2(fd[1], fileno(stderr));
        close(fd[1]);
        fprintf(stdout,"stdout\n");
        fprintf(stderr,"stderr\n");
    }
    return 0;
}

Ответы [ 3 ]

7 голосов
/ 19 октября 2010

Существует разница между FILE * s stdout и stderr и файловыми дескрипторами 1 и 2. В этом случае именно ФАЙЛЫ вызывают поведение, которого вы не ожидали. stderr не буферизируется по умолчанию, поэтому в случае ошибки вы можете распечатать сообщение наиболее надежным способом, даже если производительность этой печати замедляет общую производительность программы.

stdout, по умолчанию, буферизуется. Это означает, что у него есть массив памяти, в котором хранятся данные, которые вы сказали ему записать. Он ожидает, пока массив (называемый буфером) не будет заполнен до определенного уровня или (если он настроен для буферизации строк, что это часто), пока не увидит '\n'. Вы можете позвонить по номеру fflush(stdout); и напечатать.

Вы можете изменить настройки буферизации FILE *. man 3 setbuf имеет функции, которые делают это для вас.

В вашем примере буфер stdout содержал строку "stdout", в то время как "stderr" записывался на экран. Затем при выходе из программы все открытые FILE * сбрасываются, поэтому выводится «stdout».

4 голосов
/ 19 октября 2010

Два потока stdout и stderr могут использовать один и тот же дескриптор файла, но перед тем, как поток FILE записывает какие-либо данные в свой базовый дескриптор файла, данные сохраняются в буфере потока.Буферы в stdout и stderr не становятся одинаковыми только потому, что два потока подключены к одному и тому же дескриптору файла.

Обратите внимание, что эта буферизация выполняется потоками FILE в библиотеке stdio, а не ОСядро и его файловые дескрипторы.Там также может происходить другая буферизация, но эта проблема вызвана уровнем библиотеки stdio выше.

3 голосов
/ 19 октября 2010

Как насчет очистки стандартного вывода?

dup2(fd[1], fileno(stdout));
dup2(fd[1], fileno(stderr));
close(fd[1]);
fprintf(stdout,"stdout\n");
fflush(stdout);
fprintf(stderr,"stderr\n");

(только что попробовал, и это работает)

...