dup2, execv, каналы, разветвление и код, работающий в неправильном порядке

Так что это должно делать разветвление, дочерний процесс получает текст файла, а затем родительский процесс изменяет этот текст и записывает его в новый файл. У меня разные странности исходят от этого. Весь код примерно такой.

#include <iostream>
#include <termios.h>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>

using namespace std;

int parentPID;

int main(int argc, char* argv[]){

    parentPID = getpid();
    int pipey[2];

    int worked = pipe(pipey);
    if( worked == - 1){
        cout << "Oops.  Didn't make a pipe.";
    }

    //cout << "About to fork!!!";

    fork();

    if(getpid() != parentPID){//Only run in the child process
        char* argvec1[3] = {"cat", "colorfile.txt", (char*)0};
        dup2(pipey[1], 1);
        execv("/bin/cat", argvec1);
    }
    else{//Only run in the parent process.
        int someInt;
        cout << "In the parent process";
        pid_t status = wait(&someInt);
        dup2(pipey[0], 0);

        creat("newfile.txt", 0777);
        chmod("newfile.txt", 0777);
        int targetFile = open("newfile.txt", O_WRONLY);

        if(targetFile == -1){
            cout << "\nOops, couldn't open targetFile, ";
            perror("because ");
        }
        else{
            cout << "\nOpened target file.";
        }

        dup2(targetFile, 1);

        //char* argvec2[] = {"sed", "-e", "s/color/colour/g", (char*)0};
        //execv("/bin/sed", argvec2);
        cout << "something went terribly wrong";
    }
}

Особую тревогу вызывают три вещи, во-первых, этот фрагмент кода...

    creat("newfile.txt", 0777);
    chmod("newfile.txt", 0777);
    int targetFile = open("newfile.txt", O_WRONLY);

    if(targetFile == -1){
        cout << "\nOops, couldn't open targetFile, ";
        perror("because ");
    }
    else{
        cout << "\nOpened target file.";
    }

    dup2(targetFile, 1);

... не записывает «Открытый целевой файл» в стандартный вывод. Вместо этого он помещает его в newfile.txt, поэтому dup2 меняет вывод команд вывода, которые появляются перед ним?... если я закомментирую dup2 в конце, этого не происходит, это определенно конкретный dup2 позвоните, чтобы это произошло.

во-вторых, этот фрагмент кода...

    creat("newfile.txt", 0777);
    chmod("newfile.txt", 0777);
    int targetFile = open("newfile.txt", O_WRONLY);

    if(targetFile == -1){
        cout << "\nOops, couldn't open targetFile, ";
        perror("because ");
    }
    else{
        cout << "\nOpened target file.";
    }

    //dup2(targetFile, 1);

    char* argvec2[] = {"sed", "-e", "s/color/colour/g", (char*)0};
    execv("/bin/sed", argvec2);
    cout << "something went terribly wrong";

... вообще не выводит никакого успеха/неудачи в отношении открытия файла. Он распечатывает содержимое исходного файла, соответствующим образом измененного, но затем не завершается. Это просто сидит вечно, пока я не использую Ctrl-C, чтобы убить текущий процесс. Окончательный cout не отображается.

Наконец, это...

    creat("newfile.txt", 0777);
    chmod("newfile.txt", 0777);
    int targetFile = open("newfile.txt", O_WRONLY);

    if(targetFile == -1){
        cout << "\nOops, couldn't open targetFile, ";
        perror("because ");
    }
    else{
        cout << "\nOpened target file.";
    }

    dup2(targetFile, 1);

    char* argvec2[] = {"sed", "-e", "s/color/colour/g", (char*)0};
    execv("/bin/sed", argvec2);
    cout << "something went terribly wrong";

... не дает мне никакого вывода ни в стандартный вывод, ни в newfile.txt.

Создается впечатление, что некоторые из этих системных вызовов просто выполняются в том порядке, в каком им хочется, полунезависимо от порядка, в котором я их написал, что делает практически невозможным что-либо с ними сделать.


person user1299656    schedule 06.03.2014    source источник
comment
Ставьте новые строки в конце сообщений, а не в начале (или так же). Сообщение может не появиться на экране до тех пор, пока после него не будет добавлена ​​новая строка. Можно спорить, все ли это не так, но это общий вопрос. Вы можете даже включить << endl для принудительного вывода, но в большинстве случаев достаточно простого "\n" в конце. Кроме того, поскольку вы не создаете исполняемые программы, x-биты в разрешении 0777 неуместны — 0666 или даже 0644 были бы более разумными.   -  person Jonathan Leffler    schedule 06.03.2014
comment
Файловые дескрипторы вашего канала, скорее всего, сохранятся в файле execs. Подумайте, может ли процесс (подсказка: здесь он может быть даже родителем), чей стандартный ввод был привязан к стороне чтения канала, когда-либо увидит конец данных, если сторона записи канала не была закрыта.   -  person sjnarv    schedule 06.03.2014


Ответы (1)


Используя входной файл с именем «colorfile.txt», например:

color
color color
color color color
color color color color

Я обновил ваш код, чтобы по-другому выполнять дублирование и отладку сообщений. Самое важное изменение (как я упоминал в своем комментарии к вашему вопросу) состоит в том, чтобы закрыть сторону записи канала в родительском процессе, чтобы избежать зависания этого процесса. Также важным (в целях отладки и устранения путаницы с порядком событий) является использование 'endl' для сброса вывода. В противном случае ваши вызовы dup2 происходят, пока буферизованные данные все еще хранятся, и могут изменить назначение этих данных, по-видимому, после того, как они были записаны, поскольку запись происходит, когда базовые библиотеки сбрасывают вывод, скажем, при выходе из процесса.

Обратите внимание, что для каналов я использую термины "сторона записи" и "сторона чтения" для обозначения индексов 1 и 0 соответственно этого небольшого массива файловых дескрипторов, созданного pipe(2): стороны которому пользователь канала пишет и читает.

Эти обновления предназначены для g++ (GCC) 4.8.2 на ядре Linux 3.10.17. Предположительно другие включения и т. д. будут отличаться.

#include <iostream>
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>

using namespace std;

int main() {

    int pipey[2];

    if (pipe(pipey) == -1) {
        perror("pipe failed");
        return 1;
    }

    cout << "About to fork!!!" << endl;

    pid_t pid = fork();

    if (pid == -1) {
        perror("fork failed");
        return 1;
    }

    if (pid == 0) { // child process

        const char *av[] = { "cat", "colorfile.txt", 0 };

        cout << "In the child process" << endl;

        cout << "colorful child message before dup2" << endl;

        dup2(pipey[1], 1);
        close(pipey[1]);

        cout << "colorful child message after dup2" << endl;

        close(pipey[0]);

        execvp(av[0], (char * const *) av);

        perror("failed to exec cat");
        return 1;

    } else { // parent process.

        const char *av[] = { "sed", "-e", "s/color/colour/g", 0 };

        cout << "In the parent process" << endl;

        int targetFd = open("newfile.txt", O_CREAT|O_TRUNC|O_WRONLY, 0644);

        if (targetFd == -1){
            perror("failed to open newfile.txt");
            return 1;
        } else {
            cout << "Opened target file." << endl;
        }

        cout << "colorful parent message before dup2s" << endl;

        dup2(pipey[0], 0);
        close(pipey[0]);

        dup2(targetFd, 1);
        close(targetFd);

        cout << "colorful parent message after dup2s" << endl;

        // The soon-to-be exec'd cat process will have the read side of
        // the pipe duped to its stdin, and the child process created
        // above *will* write data that cat will see, but unless the
        // write side is closed by *all* its writers prior to exec (and
        // this parent process is one of the writers), cat will see no
        // end-of-file on its stdin.
        //
        // Note how easily this deadlock can be created, within a single
        // process.

        close(pipey[1]);

        execvp(av[0], (char * const *) av);

        perror("failed to exec sed");
        return 1;
    }
}

Когда я запускаю это, я вижу:

About to fork!!!
In the parent process
In the child process
colorful child message before dup2
Opened target file.
colorful parent message before dup2s

И содержимое выходного файла newfile.txt:

colorful parent message after dup2s
colourful child message after dup2
colour
colour colour
colour colour colour
colour colour colour colour

Если вы понимаете, почему одно сообщение красочное, а другое — яркое, вы поймете.

person sjnarv    schedule 07.03.2014