0

I am using 4 processes in which A's output will goto A1 and A1's output will go to A2 and A2 output will come out in the console. Even A1 output also will comeout in console.

  1. 1st program - A C++ program which is a random generator that will generate the output as per the requirements of A1's input and also act as a collector for stdout from the sub processes
  2. 2nd program - Python script which will take the input of A's output and will generate the output as per the requirements of A2 and the output of A1 should print in the console.
  3. 3rd program - cpp file which will take the input of A1's output and will give the output and print in the control.

I am using 2 pipes - ABtoC for A to A1, A1toA2 for A1toA2.

Here A to A1 is working and A1's output is printing in the console. But the issue is A1's output is not going to A2's input. Here is the below code I am using for this operation.

#include <vector>

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <string>
#include <sstream>

/// Entry point of process B
int procB(void) {
  // Process B writing to C
  while (!std::cin.eof()) {
    // read a line of input until EOL and store in a string
    std::string line;
    std::getline(std::cin, line);
    if (line.size() > 0)
      std::cout << line << std::endl;
  }
  std::cout << std::endl;
  return 0;
}

int main(int argc, char** argv) {
  std::vector<pid_t> kids;
  // create a pipe
  int ABtoC[2];
  pipe(ABtoC);

  int A1toA2[2];
  pipe(A1toA2);



  pid_t child_pid;
  child_pid = fork();
  if (child_pid == 0) {
    // redirect stdout to the pipe
    dup2(ABtoC[1], STDOUT_FILENO);
    close(ABtoC[0]);
    close(ABtoC[1]);
    close(A1toA2[0]);
    close(A1toA2[1]); // Close this too!

    execv("./rgen", argv);
  } else if (child_pid < 0) {
    std::cerr << "Error: could not fork\n";
    return 1;
  }


  kids.push_back(child_pid);

  child_pid = fork();
  if (child_pid == 0) {
    // redirect stdin from the pipe
    dup2(ABtoC[0], STDIN_FILENO);
    close(ABtoC[1]);
    close(ABtoC[0]);
    close(A1toA2[0]);
    close(A1toA2[1]);

    argv[0] = (char *)"python3";
      argv[1] = (char *)"a1ece650.py";
      argv[2] = nullptr;


    dup2(A1toA2[1], STDOUT_FILENO);
    close(A1toA2[1]);
    close(A1toA2[0]);
    close(ABtoC[0]);
    close(ABtoC[1]);
    execvp("python3", argv);

  } else if (child_pid < 0) {
    std::cerr << "Error: could not fork\n";
    return 1;
  }

kids.push_back(child_pid);

  child_pid = fork();
  if (child_pid == 0) {
    // redirect stdin from the pipe
    dup2(A1toA2[0], STDIN_FILENO);
    close(A1toA2[1]);
    close(A1toA2[0]);
    close(ABtoC[0]);
    close(ABtoC[1]);

    execv("./ece650-a2", argv);

  } else if (child_pid < 0) {
    std::cerr << "Error: could not fork\n";
    return 1;
  }


  kids.push_back(child_pid);
  child_pid = 0;

  // redirect stdout to the pipe
  dup2(A1toA2[1], STDOUT_FILENO);
  close(A1toA2[0]);
  close(A1toA2[1]);
  close(ABtoC[0]);
  close(ABtoC[1]);

  // start process B
  int res = procB();

  // send kill signal to all children
  for (pid_t k : kids) {
    int status;
    kill(k, SIGTERM);
    waitpid(k, &status, 0);
  }

  return res;
}

Insert ASCII graphics below:

+--------------+   +-----+             +-----+                +-----+
|Fork and Pipe| --  A.cpp stdout--stdin A1.py --stdout--stdin  A2.cpp
+--------------+.  +-----+             +-----+                +-----+
```                                       |                      |
                                          V                      V
                                        stdout                  stdout
Sindhu
  • 15
  • 3
  • You could make `procB` cleaner. `std::string line; while(std::getline(std::cin, line)) { std::cout << line << std::endl; }` - See [Why is `iostream::eof()` inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) – Ted Lyngmo Mar 20 '21 at 09:23
  • Note 2: You are also assigning 3 new pointers to `argv[]` without checking `argc` first. What if the size of `argv[]` isn't at least `3`? Undefined behavior. – Ted Lyngmo Mar 20 '21 at 09:29
  • Note 3: You should `exit` after `exec*` just in case the `exec*` fails - otherwise you will have a rouge process continuing to execute code it wasn't supposed to reach. – Ted Lyngmo Mar 20 '21 at 09:32
  • Note 4: You `close(A1toA2[1]);` then `dup2(A1toA2[1], STDOUT_FILENO);`. You could encapsulate all this in a `Pipe` `class` that does rigorous error checking and throws an exception if anything fails (as the above `dup2` must do). – Ted Lyngmo Mar 20 '21 at 09:59
  • Thank you for the response!I have removed close(A1toA2[1]) now its working. But the thing is I am not able to print the output of A1 in the console. Can you please help me resolve this – Sindhu Mar 20 '21 at 11:08
  • You're welcome. Do I read it correctly: A1 is a python script and you want the output from A1 to be written directly to the console and also to A2? So A1's output needs to be `dup2`ed twice? If very hard to keep the head on straight with all the dup's everywhere :-) I would first write a `Pipe` class to simplifiy this and probably also a `ChildProcess` class containing a `Pipe` and start from there. It's seriously easy to make mistakes when everything is in a big pile in `main` – Ted Lyngmo Mar 20 '21 at 11:44
  • I looked at it a bit more. You have a `.cpp` program that `fork() + exec*()` 3 times so there are 4 processes?. If you could make a little ASCII-drawing ([something like this](https://pastebin.com/jNJ9rmHQ)) of how you'd like them to be connected it would probably help. – Ted Lyngmo Mar 20 '21 at 13:05
  • Yeah! your understanding is correct. Totally 4 processes. 1st process is the above one which uses forks and pipe. Will execute the above one and the remaining will run as explained. I made the ASCII drawing as you mentioned, can you please tell me where can I upload that – Sindhu Mar 20 '21 at 18:38
  • Perfect. Just [edit](https://stackoverflow.com/posts/66718213/edit) your question and put it in a code block. – Ted Lyngmo Mar 20 '21 at 18:39
  • I added a guide at the bottom. Just add the ASCII graphics between the backticked lines. – Ted Lyngmo Mar 20 '21 at 19:12
  • Thank you for your response! Its very helpful. The printing issue is resolved by adding flush in cpp program also so that it worked. – Sindhu Mar 22 '21 at 14:15
  • You're welcome. You never put the ASCII drawing in the question? – Ted Lyngmo Mar 22 '21 at 21:13
  • I have done it! – Sindhu Mar 24 '21 at 04:19
  • Ok, good, but in your program, it seems like the function `procB` is supposed to read from somewhere. Is it `stdout` from `A1.py` and `A2.cpp`? The names of the started programs (`./rgen`, `a1ece650.py` and `ece650-a2`) doesn't map 1:1 to the drawing so it's a bit tricky to understand the setup exactly. – Ted Lyngmo Mar 24 '21 at 06:26

1 Answers1

0

When you launch A1, you are closing A1toA2[1] and then after that trying to dup it into stdout. Do all of the dups first, and then close what you don't need.

Tim Roberts
  • 10,104
  • 1
  • 12
  • 14
  • I removed as you suggested and the input is flowing from A to A1,A1 to A2 but the output of A1 is printing in the console now. I used sys.stdout.flush() after the print in python script. still its not printing – Sindhu Mar 20 '21 at 08:03