【问题标题】:How to correctly receive data from pipes?如何正确接收来自管道的数据?
【发布时间】:2013-08-15 21:41:36
【问题描述】:

所以我写了一个程序,使用管道和 execl 来做一些算术。我不确定如何调试管道和不同的进程,但据我所知,这与我的管道读取数字有关。所以到目前为止我的设置是创建孩子,并根据他们给定的操作,他们执行到不同的程序,这些程序将计算管道中的写入值。我不知道在它读取结果之前将它的值写入孩子之后,我是否应该在父母中实现等待或其他东西。我不断得到 Z 作为我的输出。

所以这是我要执行的文件之一,其他文件看起来完全一样,只是显示了相应的操作:

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>

using namespace std;

main(int argc, char *argv[])
{
    int x, y, z;
    while (read(0, (char *)&x, sizeof(int)) &&
           read(3, (char *)&y, sizeof(int))) {
        z = x * y;
        if (argc > 1)
            cerr << "multiply: " << x << " * " << y << " = " << z << endl;
        write(1, (char *)&z, sizeof(int));
    }
}

这是我的代码,它实际上会进行计算,我认为管道设置正确。只是对管道设置的一点解释,以节省时间。子 0 - 从管道 0 1 读取并写入 2。子 1 从管道 2 和 3 读取并写入 4。父写入 0 1 3 并从 4 读取。我的代码:

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

using namespace std;

const int MAX =21;
int pipes[MAX][2];
char operations[MAX];

int main()
{
    int a=0;
    int n;
    fstream datafile;
    pid_t pid;
    string line;
    datafile.open("data1.txt");
   

   if(datafile)
    {

        string input;
        getline(datafile, input);
        
        for(int i=0; i< input.size(); i++)
        {

    
            if (input[i] == '*'|| input[i] == '/'||input[i] == '+'||input[i] == '-')
            {
      
                operations[a] = input[i];
                a++;

            }

        }
      n = (a);

        for(int i =0; i<(2*n+1); i++)
           pipe(pipes[i]);

        for (int i=0; i <n; i++)
        {    
           pid = fork();
            if(pid == 0)
            {
             
                close(0);
                dup(pipes[2*i][0]);
                close(3);
                dup(pipes[2*i+1][0]);
                close(1);
                dup(pipes[2*i+2][1]);
              
            
                    switch(operations[i])
                    {
                    case '+':
                        execl("add","add", NULL);
                    case '-': 
                        execl("subtract","multiply", NULL);
                    case '*':
                        execl("multiply","multiply", NULL);
                    case '/':
                        execl("divide","divide", NULL);
                    
                    }

                 cout<< "No match for operation!";
            }
            else if(pid <0)
            cerr<<"Fork has failed";
          }
    
        int x, y, z;

        for(int i=0; i<3; i++)
          {
            getline(datafile,line);
            istringstream ins(line);
            ins >> x >> y >> z;

            write(0,(char *)&x, sizeof(x));
            write(3,(char *)&z, sizeof(z));
            write(1,(char *)&y, sizeof(y));
          }
          
          close(0);
          close(3);
          close(1);
        }  
        
            else
                cerr<<"Error reading file";
          


          datafile.close();
          
            int result;
            while(read(pipes[2*n][1],(char *)&result,sizeof(result)))
                cout<<result<<endl;
    
        
        
 
        



}

数据文件可以是这样的:

a * b *c

30 40 50

100 3 6

【问题讨论】:

  • 只对一个孩子有效吗?每个孩子只能使用一根管子吗?没有execl 可以吗?如果其中任何一个的答案都是“否”,那么您就是在使这个问题变得不必要地复杂。
  • @Beta 对不起,我的意图不是让它变得复杂,我只是想确保我解释了我的问题。简单的答案是否定的,它不起作用。我只对父级的写入部分进行了调试,似乎值正在输入但结果没有返回,它只返回 Z。
  • Simplify this code. 精简到产生错误的最简单示例。 1)这将使我们的工作变得更容易。 2)您可能会在削削时发现错误。 3) 重要的是要养成简化代码的习惯,从简单到复杂,每一步都测试
  • @Beta 我确实开始很简单,只需确保正确读取正确的值,然后添加管道。我不确定如何在不违反给我的指示的情况下进一步简化程序。我刚刚调试了程序,似乎所有内容都是从父级正确写入的。但是当我要求 gdb 打印结果时,我得到 1。而且我的父进程似乎没有结束
  • 好吧,发一个完整的例子,我们试试看。

标签: c++ linux exec fork pipe


【解决方案1】:

让我们简化这段代码。 没有操作——仍然不起作用。只有一个孩子——还是不行。只有一根管子——还是不行。没有文件 I/O - 仍然不起作用。我们现在尝试将数字 30 从父级传递给子级:

  int pipes[1][2];

  pid_t pid;

  pipe(pipes[0]);

  pid = fork();
  if(pid == 0)
    {
      cout << "child here" << endl;
      close(0);
    }
  else if(pid <0)
    cerr<<"Fork has failed";

  cout << "parent here " << endl;

  int x = 30;
  write(0,(char *)&x, sizeof(x));
  close(0);

  int result;
  read(pipes[0][1],(char *)&result,sizeof(result));
  cout << "result is " << result << endl;

看到错误了吗?让我们更进一步,完全移除管道通信:

pid_t pid;
pid = fork();
if(pid == 0)
  {
    cout << "child here" << endl;
  }
else if(pid <0)
  cerr<<"Fork has failed";

cout << "parent here " << endl;

看到错误了吗?我们修复它:

pid_t pid;
pid = fork();
if(pid == 0)
  {
    cout << "child here" << endl;
    return(0);
  }
else if(pid <0)
  cerr<<"Fork has failed";

cout << "parent here " << endl;

然后把管子放回去:

  int pipes[1][2];

  pid_t pid;

  pipe(pipes[0]);

  pid = fork();
  if(pid == 0)
    {
      cout << "child here" << endl;

      close(0);

      int result;
      read(pipes[0][1],(char *)&result,sizeof(result));
      cout << "result is " << result << endl;
      return(0);
    }
  else if(pid <0)
    cerr<<"Fork has failed";

  cout << "parent here " << endl;

  int x = 30;
  write(0,(char *)&x, sizeof(x));
  close(0);

看到错误了吗?修复管道错误,然后恢复最多 2 个孩子和 5 个管道。 分别测试操作的东西,然后拼接进去。

我相信这展示了简化代码的力量。

【讨论】:

  • +1 我没有检查解决方案的有效性,但快速浏览一下它看起来还不错。不过,这是制定解决方案的绝佳方法,如果可以的话,+10。
  • @beta 我照你说的做了,注意到了这些错误,但我坚持最后一个。我看到它输出了错误的数字,但是它来自哪里,我需要转换结果的输出吗?
  • @Janae:错误在于代码操纵0(即stdin)而不是pipes[0](实际管道)。它应该写入pipes[0][1] 并从pipes[0][0] 读取。
  • @Janae:真的吗?这个对我有用。编辑您的问题以附加新代码,我们来看看。
  • @Beta 我必须说,我怀疑你的回答,但我的程序正在运行。我实际上并没有从头开始,但我确实运行了您编写的所有代码来查看问题。然后我用它来修改我的代码,玩弄一些东西,然后它就开始工作了。非常感谢。
猜你喜欢
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 2019-02-17
相关资源
最近更新 更多