2

我不会撒谎的。这是一个家庭作业问题。然而,就我而言,这些点都不见了,宝贝不见了。现在,我只是在寻找答案,因为我 - 认为 - 我可能疯了。

该程序的目标是以ps -A | grep (inputstring) | wc -l类似于 shell 的方式执行命令。因此,我生成了这些进程,并让它们相互等待。最新的流程,曾孙,execlp("ps","ps","-A",NULL)它用ps -A流程代替了自己。在它之前execlp,我确保它的标准输出将进入管道输出。行中的下一个进程是wait()ing,并且已经自行设置,以便输入管道进入标准输入,标准输出进入输出管道,它将执行 grep,依此类推。

我几乎可以肯定我已经正确设置了它。然而……程序确实如此。不是。工作。

#include <stdlib.h>
#include <iostream>
#include <string>

#define MAXLINE 1500
#define READ 0
#define WRITE 1

using namespace std;

int main( int argc, char** argv ) {
//* start of input block
if ( argc != 2 ) {
    cout << "Usage: ./a.out arg1" << endl;
    return 0;
}
string in = argv[1];
// end of input block */
int pipeA[2], pipeB[2], pid, stat;

// get our first set of pipes
if ( pipe(pipeA) < 0 ) {
    cerr << "Pipe error.\n";
    exit(-1);
}
if ( pipe(pipeB) < 0 ) {
    cerr << "Pipe error.\n";
    exit(-1);
}

// make the first fork
if ( (pid = fork() ) < 0 ) { cerr << "Fork error.\n"; exit(-1); }

if ( pid > 0 ) {    // parent case
    wait(&stat);
} else {            // child case
    if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
    if ( pid > 0 ) {    // child
        wait(&stat);
        dup2(pipeA[READ],READ);
        execlp("wc","wc","-l",NULL);
    } else {    // grand-child
        if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
        if ( pid > 0 ) {    // still grand-child
            wait(&stat);
            dup2(pipeB[READ],READ);  
            dup2(pipeA[WRITE],WRITE); 
            close(pipeB[READ]);
            execlp("grep","grep",in.c_str(),NULL);
        } else {    // great grand-child
            dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1]
            close(READ);
            close(pipeB[READ]);
            execlp("ps", "ps", "-A", NULL);
        }
    }
}
return 0;
}

编辑:更改为我的代码的两管变体。

4

2 回答 2

3

我几乎可以肯定这就是你想要做的。提前为草率的编码道歉。这里有点晚了,我现在真的应该睡觉了:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>

#define READ 0
#define WRITE 1

// ps -A | grep argv[1] | wc -l

int main( int argc, char** argv )
{
    // start of input block
    if ( argc != 2 )
    {
        std::cout << "Usage: ./a.out arg1" << std::endl;
        return 0;
    }
    
    // make local copy of argument
    std::string in = argv[1];
    int fd1[2], fd2[2], pid;
    
    // allocate two pipe sets
    if (pipe(fd1) < 0 || pipe(fd2) < 0)
    {
        perror("Failed to create pipe.");
        return EXIT_FAILURE;
    }
    
    // launch first child process.
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(1)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // wc -l process. 
        //  stdin  = fd2(read)
        close(fd1[READ]);
        close(fd1[WRITE]);
        close(fd2[WRITE]);
        dup2(fd2[READ],STDIN_FILENO);
        execlp("wc","wc","-l",NULL);
    }
    
    // fork again. this time for grep
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(2)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // grep argv[1] process.
        //  stdin  = fd1(read)
        //  stdout = fd2(write)            
        close(fd1[WRITE]);
        close(fd2[READ]);
        dup2(fd2[WRITE], STDOUT_FILENO);
        dup2(fd1[READ], STDIN_FILENO);
        execlp("grep", "grep", in.c_str(), NULL);
    }
    
    //  fork once more. this time for ps -A
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(3)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // ps -A process.
        //  stdout = fd1(write)
        close(fd2[WRITE]);
        close(fd2[READ]);
        close(fd1[READ]);
        dup2(fd1[WRITE], STDOUT_FILENO);
        execlp("ps", "ps", "-A", NULL);
    }
    
    int stat=0;
    wait(&stat);

    return EXIT_SUCCESS;
}

在我的系统上,ps -A报告了 141 行,其中 41 行中有单词System,只需运行即可验证ps -A | grep System | wc -l。上面的代码生成完全相同的输出。

于 2013-10-14T09:35:25.980 回答
0

我不确定,但也许在等待孩子之前调用 dup2 可以解决管道问题。

我不确定的原因是它通常 stdin 和 stdout 是缓冲的,所以我想即使你在孩子完成跑步后将管道与它们连接起来,你也应该得到相同的结果,但也许(如果有人知道答案这请纠正我)标准输入和标准输出的缓冲区在子进程结束时被擦除。

另外,您能否更新问题中的代码以包含带有两组管道的修改代码?

于 2013-10-14T09:35:04.593 回答