0

My requirements are simple: start a process, wait for it to finish, then capture and process it's output.

For the longest time I've been using the following:

struct line : public std∷string {
    friend std∷istream& operator>> (std∷istream &is, line &l) {
        return std∷getline(is, l);
    }
};

void capture(std::vector<std::string> &output, const char *command)
{
    output.clear();
    FILE *f = popen(command, "r");
    if(f) {
        __gnu_cxx::stdio_filebuf<char> fb(f, ios∷in) ;
        std::istream fs(&fb);
        std::istream_iterator<line> start(fs), end;
        output.insert(output.end(), start, end);
        pclose(f);
    }
}

And it works really well on single threaded programs.

However, if I call this function from inside a thread, sometimes the popen() call hangs and never return.

So, as a proof-of-concept I replaced the function for this ugly hack:

void capture(std::vector<std::string> &output, const char *command)
{
    output.clear();
    std::string c = std::string(command) + " > /tmp/out.txt";
    ::system(c.c_str());
    ifstream fs("/tmp/out.txt", std::ios::in);
    output.insert(output.end(), istream_iterator<line>(fs), istream_iterator<line>());
    unlink("/tmp/out.txt");
}

It's ugly but works, however it kept me wondering what would be the proper way to capture a process output on a multi-threaded program.

The program runs on linux in a embedded powerquiccII processor.

Akobold
  • 936
  • 8
  • 25

1 Answers1

2

See this: popen - locks or not thread safe? and other references do not seem conclusive that popen() needs to be thread-safe, so perhaps since you are using a less-popular platform, your implementation is not. Any chance you can view the source code of the implementation for your platform?

Otherwise, consider creating a new process and waiting upon it. Or hey, stick with the silly system() hack, but do handle its return code!

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • The libc I got is a pre compiled binary, without sources. – Akobold Feb 27 '13 at 11:33
  • Then I think if you're aiming for a more "pure" solution, you ought to fork a process (which popen does anyway, so we're not talking orders-of-magnitude more overhead), and call popen from there. Or do it without popen: http://stackoverflow.com/a/6744256/4323 – John Zwinck Feb 27 '13 at 11:40
  • Ok, I will try the "pure" approach. Thanks – Akobold Feb 27 '13 at 11:43
  • Or do manually the  `pipe`, `fork`, `dup2`, `execve` syscalls done by `popen` – Basile Starynkevitch Feb 27 '13 at 12:40
  • Heck, for that matter, maybe you can find a suitably-licensed open-source popen() implementation that is thread-safe and just use that. – John Zwinck Feb 27 '13 at 12:49