Проблема с каналами между процессами отца и сына

Используя каналы, отец читает из стандартного ввода и отправляет его дочернему процессу с помощью каналов, чтобы дочерний процесс мог выполнить подсчет слов для ввода. Задачи с открытой и закрытой трубой p[0] и p[1]. Почему я не могу сделать dup2(p[1],1), а затем написать(1,buffer,1)? Это работает, только если я пишу (p[1],buffer,1) без dup2(p[1],1).

int main(int argc, char **argv){
    int p[2];
    int n;
    char buffer[1024];
    pipe(p);
    if(!fork()){
        close(p[1]);    
        dup2(p[0],0);
        close(p[0]);
        execlp("wc","wc",NULL);
        _exit(0);
    }
    else{
        close(p[0]);
        dup2(p[1],1);
        while((n=read(0,buffer,1))>0){
            write(1,buffer,1);
        }
        close(p[1]);
        wait(NULL);
    }
    return 0;
}

person Diogo Silva    schedule 11.04.2019    source источник


Ответы (1)


Почему я не могу сделать dup2(p[1],1), а затем написать(1,buffer,1)?

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

Это работает, только если я пишу (p[1],buffer,1) без dup2(p[1],1).

Это зависит от того, что вы подразумеваете под «работает». Когда я запускаю ваш исходный код, программа никогда не выводит никаких результатов и никогда не завершается, но это не означает, что записи родителя не привели к успешной отправке данных дочернему элементу.

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

Если родитель не дублирует конец записи канала, то на нем открыт только один файловый дескриптор, и он есть у дочернего элемента. Оба закрывают свои в соответствующее время. Но в коде, который вы представляете, родитель дублирует p[1] на файловый дескриптор 1, так что он имеет два открытых файловых дескриптора, ссылающихся на конец канала. Он всегда закрывает только p[1], оставляя файловый дескриптор 1 открытым, поэтому дочерний процесс продолжает ждать ввода данных.

Родитель закроет FD 1, если он выйдет, позволив дочернему завершить работу, но он ожидает завершения дочернего процесса первым. Это одна из наиболее распространенных ошибок взаимоблокировки, связанных с перенаправлением ввода-вывода. Я бы предложил просто не дублировать родительский дескриптор файла, поскольку дублирование FD 1 без необходимости не позволяет ему использовать свой стандартный вывод для любых других целей. Но если он обманывает, то он должен закрыть оба файловых дескриптора, прежде чем дочерний процесс завершится.

person John Bollinger    schedule 11.04.2019