I am developing an application where I need to launch and stop a variety of different executables depending on user input. I would like my "core" program to run as normal whilst these executables run, i.e not wait for their termination which could theoretically be infinte. As well as this I need to be able to receive std_out and send std_in to these executables.
At the moment I have a set up where I have a process manager class:
class ProcessManager {
private:
std::vector<patchProcess> processList;
boost::process::group processGroup;
public:
ProcessManager();
void addNew(std::string name,std::string command, std::string args);
void killAll();
void printAllIn();
};
Where patch process is:
struct patchProcess {
std::string name;
boost::process::child *process;
std::shared_ptr<boost::process::ipstream> procOutStream;
};
Where I can launch / add a new process with the function
void bbefxProcessManager::addNew(std::string name, std::string command, std::string args) {
LOG(info) << "Creating process for patch " << name;
patchProcess pp;
pp.name = name;
pp.procOutStream = std::shared_ptr<boost::process::ipstream>(new boost::process::ipstream);
boost::process::child newProc(command,args,processGroup,boost::process::std_out > *pp.procOutStream);
pp.process = &newProc;
processList.push_back(pp);
}
And my printing attempts:
void bbefxProcessManager::printAllIn() {
std::string line;
for (auto &proc : processList) {
std::getline(*proc.procOutStream, line);
std::cout << line << std::endl;
}
}
This code sucessfully launches the process, however readAllIn gives me a blank output. I have a feeling that I am doing something horribly wrong with std::shared_ptr<boost::process::ipstream> procOutStream;
. My rationale behind this is that I am using push_back
into my processList (vector of struct), so it should be copyable. I can get the output of a test exec without using the patchProcess struct and these shared pointers but that makes mangement hard / messy. I can also confirm that if I attempt to read the output in the addNew function with something like:
while(true) {
*pp.procOutStream >> line;
std::cout << line << std::endl;
}
I get the output of my executable. So does this hint something is going wrong with copy constructors?
I found that I was overlooking the
boost::process::child *process;
struct member , when using that with a shared pointer as with theipstream
I get the expected results.I am going to leave this question open though because I am still not entirely happy I am doing this in the correct way and would appreciate some input.
Before your edits, I started doing some work on a truly async approach:
Let's get the formalities out of the way:
Now lets create a
ProcessManager
that runs all processes on a singleio_service
that is shutdown in the destructor.The IO service is used to schedule all the work (like asynchronous IO). I've
strand
that correctly synchronizes operations with respect to a child.Demos
The most naive run would be:
Which, predictably returns after doing nothing. Next, we try
Which predictably waits 3 seconds before exiting. It prints:
Let's do some IO:
Live On Coliru
Prints
To really drive the point home that the processes and their IO are synchronous, we can replace
with something more time-varied:
Now, to make it really challenging, let's add another child process and send the output of the
ls
to the otherchild
:Live On Coliru
Now, on Coliru the listing is too small to be interesting, but on my system you get output like: