I have some simple application:
//first.exe
int main()
{
std::cout << "1" << std::endl;
std::cout << "2" << std::endl;
std::cout << "3" << std::endl;
std::cin.get();
return 0;
}
And I want to invoke a callback in separate application when "2" occurs in stdout of application run as a child process:
//second.exe
int main()
{
boost::asio::io_context context;
boost::process::async_pipe out(context);
boost::asio::streambuf buffer;
boost::process::child("first.exe", boost::process::std_out > out);
boost::asio::async_read_until(out, buffer, "2", [](boost::system::error_code code, std::size_t size)
{
//do something
});
context.run();
return 0;
}
The problem is that I have to press any button in parent process due to std::cin.get()
in child process to make io_context execute callback function. Do you have any suggestions to make it work as intended?
In this case I don't think you need to do a thing (the std::cin
read might just fail):
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>
int main()
{
namespace bp = boost::process;
boost::asio::io_context context;
bp::async_pipe out(context);
bp::child c("./first.exe", bp::std_out > out);
boost::asio::streambuf buffer;
boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
if (code) {
std::cerr << "Oops: " << code.message() << std::endl;
} else {
std::cerr << "received: " << size << " bytes: ";
auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());
std::clog << std::quoted(std::string(b, m)) << std::endl;
std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;
buffer.consume(size);
}
});
context.run();
return c.exit_code();
}
Prints
received: 3 bytes: "1
2"
Note that we read more bytes: "
3
"
For cleanness, you could simply close std_in
:
bp::child c("./first.exe", bp::std_out > out, bp::std_in.close());
And to be proper, also add the context for async io:
bp::child c("./first.exe", bp::std_out > out, bp::std_in.close(), context);
Those all work (see live).
What if you actually need to supply input to get output? Or you need to supply input based on the output? Then the commenter is right: attach a pipe to std_in (or have a buffer be written asynchronously).
first.cpp
#include <iostream>
int main() {
using namespace std;
string s;
while (cin >> s)
cout << "reversed: " << string(s.rbegin(), s.rend()) << endl;
}
main.cpp
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>
int main() {
namespace bp = boost::process;
boost::asio::io_context context;
bp::async_pipe out(context);
std::string i = "hello\nwo2rld\n";
bp::child c("./first.exe", bp::std_out > out, bp::std_in < boost::asio::buffer(i), context);
boost::asio::streambuf buffer;
boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
if (code) {
std::cerr << "Oops: " << code.message() << std::endl;
} else {
std::cerr << "received: " << size << " bytes: ";
auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());
std::clog << std::quoted(std::string(b, m)) << std::endl;
std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;
buffer.consume(size);
}
});
context.run();
return c.exit_code();
}
Prints
received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"
Both synchronously and asynchronously:
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>
int main() {
namespace bp = boost::process;
boost::asio::io_context context;
bp::async_pipe out(context), in(context);
bp::child c("./first.exe", bp::std_out > out, bp::std_in < in, context);
boost::asio::write(in, boost::asio::buffer("hello ", 6));
boost::asio::streambuf buffer;
boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
if (code) {
std::cerr << "Oops: " << code.message() << std::endl;
} else {
std::cerr << "received: " << size << " bytes: ";
auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());
std::clog << std::quoted(std::string(b, m)) << std::endl;
std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;
buffer.consume(size);
}
});
boost::asio::async_write(in, boost::asio::buffer("wo2rld\n", 7), [&](boost::system::error_code code, std::size_t size) {
if (code) {
std::cerr << "Oops: " << code.message() << std::endl;
} else {
std::cerr << "sent: " << size << " bytes: ";
}
});
context.run();
return c.exit_code();
}
Printing again:
sent: 7 bytes: received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"