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 来终止当前进程。不显示最终结果。

最后,这...

    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。

感觉这些系统调用中的一些只是按照他们感觉的任何顺序执行,半独立于我编写它们的顺序,因此几乎不可能对它们做任何事情。

4

1 回答 1

0

使用名为“colorfile.txt”的输入文件,例如:

color
color color
color color color
color color color color

我更新了您的代码,以不同的方式执行其 dup2-ing 和调试消息。最重要的更改(正如我在对您的问题的评论中提到的)是关闭父进程中管道的写入端,以避免该进程挂起。同样重要的是(出于调试目的,以及处理关于事件顺序的混乱)是使用 'endl' 刷新输出。否则,您的 dup2 调用会在缓冲数据仍然保留时发生,并且可以更改该数据的目的地,显然是在写入之后,因为写入发生在底层库刷新输出时,例如在进程退出时。

请注意,对于管道,我使用术语“写入端”和“读取端”分别指代由pipe(2)创建的文件描述符的小数组的索引 1 和 0 :管道用户写入的边到,并从中读取。

这些更新针对 Linux 3.10.17 内核上的 g++ (GCC) 4.8.2。大概其他人的包含等会有所不同。

#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

如果您了解为什么一条消息是丰富多彩的,而另一条消息是丰富多彩的,那么您就会明白这一点。

于 2014-03-07T14:53:48.550 回答