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

0

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

#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.

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

  • 0
    Ставьте новые строки в конце сообщений, а не (или так же) в начале. Сообщение может не появиться на экране, пока после него не будет добавлена новая строка. Независимо от того, что все это не так спорно, но это общая проблема. Вы можете даже включить << endl для принудительного вывода, но в большинстве случаев достаточно простого "\n" в конце. Кроме того, поскольку вы не создаете исполняемые программы, x-биты в разрешении 0777 неуместны - 0666 или даже 0644 были бы более разумными.
  • 0
    Файловые дескрипторы вашего канала, скорее всего, сохранятся через execs. Подумайте, будет ли процесс (подсказка: может даже быть родительским здесь), чей stdin был связан со стороной «чтения» канала, когда-либо видел конец данных, если сторона «записи» канала не была закрыта.
Теги:
fork
system-calls
dup2

1 ответ

0

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

color
color color
color color color
color color color color

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

Обратите внимание, что для труб я использую термины "сторона записи" и "сторона чтения", чтобы соответственно ссылаться на индексы 1 и 0 этого небольшого массива файловых дескрипторов, созданных каналом (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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню