2

So I wrote a program using pipes and execl to do some arithmetic. I'm not sure how to debug pipes and different processes, but from what I can see it has to have something to do with my pipes reading the numbers. So my setup so far is the children are created, and based on thier given operation, they execl to different programs that will calculate the written values in the pipe. I don't know if I should implement a wait or something in the parent after it has written its values to the children before it reads the result. I keep getting Z as my output.

So this is one of the files I'm execl to and the other files look exactly the same it just shows its corresponding operation:

#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));
    }
}

This is my code, which would actually be doing the calculating, which I think the pipes are set up correctly. Just a little explanation on the pipe setup, to save time. Child 0 -- reads from pipe 0 1 and writes to 2. Child 1 reads from pipe 2 and 3 and writes to 4. The parent writes to 0 1 3 and reads from 4. My code:

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



}

datafile can be this:

a * b *c

30 40 50

100 3 6

Community
  • 1
  • 1
Janae
  • 65
  • 2
  • 5
  • Does it work with only one child? Does it work with only one pipe per child? Does it work without `execl`? If the answer to any of these is "no", then you are making this question unnecessarily complicated. – Beta Aug 14 '13 at 05:25
  • @Beta Sorry my intention wasn't to make it complicated, I just wanted to make sure I explained my problem. The simple answer is no it does not work. I did the debugging for just the write part of the parent, it seems the values are going in but the result is not returning, it only return Z. – Janae Aug 14 '13 at 05:35
  • [**Simplify this code.**](http://sscce.org/) Whittle it down to the simplest example that produces the error. 1) It will give us an easier job to do. 2) You may spot the bug while whittling. 3) It is important to get into the habit of simplifying code, and of building up from simple to complex, *testing at every step*. – Beta Aug 14 '13 at 05:43
  • @Beta I did start off simple by just making sure the correct values were being read properly and then added the pipes. I' nott sure how I can simplify the program more than it is, without violating the directions given to me. I just debugged the program and it seems like everything is being written from the parent properly. But when I ask gdb to print result I get 1. Also it seems my parent process isn't ending – Janae Aug 14 '13 at 05:57
  • All right, just post a complete example, and we'll give it a try. – Beta Aug 14 '13 at 06:07
  • @Beta Do you know what would cause my output to be formatting characters, and also adding these characters to my text file every time I run my program. Looks like this in the output `¶ ô` and these symbols are added to my text file `¬ ¶`. I changed the `eof` to `while(getline(datafile,line)`. I haven't seen this happen before, and I tried to search it but had no luck – Janae Aug 14 '13 at 12:35
  • I can think of a couple of possibilities. Post a complete example, so that we can copy, paste, compile and run. – Beta Aug 14 '13 at 13:59
  • @Beta I posted the full program – Janae Aug 14 '13 at 14:15
  • If you fork, you should wait. Intead of `dup`, try `dup2`. It's new and improved and gives you more control. – William Pursell Aug 14 '13 at 16:14

1 Answers1

1

Let's simplify this code. No operations -- still doesn't work. Only one child -- still doesn't work. Only one pipe -- still doesn't work. No file I/O -- still doesn't work. We are now trying to pass the number 30 from the parent to the child:

  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;

See the bugs? Let's go one step further, and remove the pipe communication entirely:

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

cout << "parent here " << endl;

See the bug? We fix it:

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;

And put the pipe back in:

  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);

See the bug? Fix the pipe bug, then work back up to 2 children and 5 pipes. Test the operation stuff separately, then splice it in.

I trust this demonstrates the power of simplifying code.

Beta
  • 96,650
  • 16
  • 149
  • 150
  • +1 I didn't check the validity of the solution, but on a quick glance it looks okay. An excellent approach to laying out a solution, though, so +10 if I could. – William Pursell Aug 14 '13 at 16:13
  • @beta I did what you said and noticed the bugs, but I'm stuck on the last one. I see that it is outputting the wrong number, but where does it come from, do I need to convert the output of result? – Janae Aug 14 '13 at 16:56
  • @Janae: The bug is that the code manipulates `0` (which is `stdin`) rather than `pipes[0]` (which is an actual pipe). It should write to `pipes[0][1]` and read from `pipes[0][0]`. – Beta Aug 14 '13 at 17:09
  • @Janae: Really? It works for me. Edit your question to append the new code and we'll take a look. – Beta Aug 14 '13 at 18:07
  • @Beta I must say, I doubted your answer, but my program is working. I didn't actually start from scratch but I did run all of the codes you wrote to see the problems. Then I used that to modify my code, played around with things, and out of no where it started working. Thanks alot. – Janae Aug 14 '13 at 20:06