2

I am stuck with a problem for my assignment. I am trying to execute 3 concurrent processes (in C++) out of which 2 of them are Python programs and one of them is C++ program.

My C++ program (sample.cpp):

#include <unistd.h>
#include <stdio.h>
#include <string.h>  
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector> 
#include <signal.h>

using namespace std;

int main()
{
    while (true)
    {
        cout << "lol" << endl;
        sleep(2);
    }
    return 0;
}

My Python program 1 (sample.py):

import sys

while True:
    line = sys.stdin.readline().strip()
    print "Python says: " + str(line)

My Python program 2 (sample2.py):

import sys

while True:
    line = sys.stdin.readline().strip()
    print "Python 2 says: " + str(line)

Here is my driver C++ program which forks processes:

#include <unistd.h>
#include <stdio.h>
#include <string.h>  
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector> 
#include <signal.h>

using namespace std;

int main()
{
    vector<pid_t> kids;

    int fd[2];
    if (pipe(fd) < 0)
    {
        cout << "Error"; 
        return 1; 
    }

    int fd2[2];
    if (pipe(fd2) < 0)
    {
        cout << "Error";
        return 1;
    }

    pid_t pid;

    pid = fork();
    if (pid == 0)
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[1]);
        close(fd[0]);

        while (true)
        {
            execvp("./sample", NULL);
        }
    }
    else
    {
        kids.push_back(pid);

        pid = fork();
        if (pid == 0)
        {
            dup2(fd[0], STDIN_FILENO);
            close(fd[0]);
            close(fd[1]);

            dup2(fd2[1], STDOUT_FILENO);
            close(fd2[1]);
            close(fd2[0]);

            char * python = "/usr/bin/python";
            char * pythonProgram = "./sample.py"; 
            char * pythonArgs[] = {python, pythonProgram, NULL, NULL};
            execvp(python, pythonArgs);
        }
        else
        {
            kids.push_back(pid);
            pid = fork();
            if (pid == 0)
            {
                dup2(fd2[0], STDIN_FILENO); 
                close(fd2[0]);
                close(fd2[1]);

                char * python = "/usr/bin/python";
                char * pythonProgram = "./sample2.py"; 
                char * pythonArgs[] = {python, pythonProgram, NULL, NULL};
                execvp(python, pythonArgs);
            }
            else
            {
                kids.push_back(pid);
            }
        }
    }

    close(fd[0]);
    close(fd[1]);
    close(fd2[0]);
    close(fd2[1]);

    for (pid_t k : kids) 
    {
        int status;
        //kill (k, SIGTERM);
        waitpid(k, &status, 0);
    }
}

When I run this program, I am expected to see "Python 2 says: Python says: lol". However, I see nothing (complete blank)... it just hangs. What am I doing wrong? I tried looking up a lot of things but no luck.

halfer
  • 18,701
  • 13
  • 79
  • 158
csGeek
  • 43
  • 3

1 Answers1

1

The while loop around the start of ./sample is pointless unless you expect execvp to fail. A successful call to exec* will never return. The actual call to execvp is wrong too:

execvp("./sample", NULL);

the second argument should be a char *const[].

You should add error handling for execvp:s (like a line with std::exit(1)). Otherwise if execvp fails, you'll have child processes running in the main flow of the program.

The python programs needs to be run unbuffered or else it will take a long time for the messages to appear. You should also check if the readline succeeded.

sample.py

import sys

while True:
    line = sys.stdin.readline().strip()
    if not line: break
    print "Python says: " + str(line)

sample2.py

import sys

while True:
    line = sys.stdin.readline().strip()
    if not line: break
    print "Python 2 says: " + str(line)

driver.cpp

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

int main()
{
    vector<pid_t> kids;

    int fd[2];
    if (pipe(fd)==-1)
    {
        clog << "Error\n";
        return 1;
    }

    int fd2[2];
    if (pipe(fd2)==-1)
    {
        clog << "Error\n";
        return 1;
    }

    pid_t pid;

    pid = fork();
    if (pid == 0)
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[1]);
        close(fd[0]);

        char* const args[] = { NULL };
        execvp("./sample", args);
        std::clog << "sample failed\n";
        std::exit(1);
    }
    else
    {
        kids.push_back(pid);

        pid = fork();
        if (pid == 0)
        {
            dup2(fd[0], STDIN_FILENO);
            close(fd[0]);
            close(fd[1]);

            dup2(fd2[1], STDOUT_FILENO);
            close(fd2[1]);
            close(fd2[0]);

            char const* python = "/usr/bin/python";
            char const* pythonProgram = "./sample.py";
            char const* pythonArgs[] = {python, "-u", pythonProgram, NULL};
            execvp(python, const_cast<char* const*>(pythonArgs));
            std::clog << "sample.py failed\n";
            std::exit(1);
        }
        else
        {
            kids.push_back(pid);
            pid = fork();
            if (pid == 0)
            {
                dup2(fd2[0], STDIN_FILENO);
                close(fd2[0]);
                close(fd2[1]);

                char const* python = "/usr/bin/python";
                char const* pythonProgram = "./sample2.py";
                char const* pythonArgs[] = {python, "-u", pythonProgram, NULL};
                execvp(python, const_cast<char* const*>(pythonArgs));
                std::clog << "sample2.py failed\n";
                std::exit(1);
            }
            else
            {
                kids.push_back(pid);
            }
        }
    }

    close(fd[0]);
    close(fd[1]);
    close(fd2[0]);
    close(fd2[1]);

    for (pid_t k : kids)
    {
        int status;
        //kill (k, SIGTERM);
        waitpid(k, &status, 0);
    }
}
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50
  • I don't know what you mean by not reading from pipes. All I am trying to do is redirect all output from sample.cpp to sample.py to sample2.py by dup2-ing stdin/stdout. What do you mean by reading from pipes? Also I don't quite understand what you mean by feeding a string? Are you saying the python programs need arguments? If so, the sole purpose of the python programs is to read from stdin and produce to stdout (and not take any arguments). – csGeek Nov 04 '18 at 16:31