问题
I am using boost::process::child
and boost::process::async_pipe
to start an application and read asynchronously (through the means of boost::asio
) everything that app outputs on screen whenever this happens.
I want to check also if the application is alive by using child::running()
method; if not running I'd like to read the exit code using child::exit_code
.
This is very useful ESPECIALLY as it is a way to be notified about an application crashing or exiting unexpectedly (I could not find a better way); when the app exits the callback is called with boost::system::error_code
set.
Do you know if I can use these two methods inside the callback called by async_pipe::async_read_some
?
In general the much more simple question would be if child::running()
and child::exit_code()
are thread safe (in both Windows and Linux).
namespace bp = boost::process;
char my_buffer[1024];
boost::asio::io_service io;
bp::async_pipe in_pipe(io);
void handle_pipe_read(const boost::system::error_code &ec, std::size_t bytes_transferred);
void schedule_read() {
in_pipe.async_read_some(
boost::asio::buffer(my_buffer),
boost::bind(&handle_pipe_read,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_pipe_read(
const boost::system::error_code &ec,
std::size_t bytes_transferred
)
{
// Q: Is this call possible? 'handle_pipe_read' can run in any thread
if(c->running())
std::cout << "I am alive" << std::endl;
else
std::cout << "EXIT CODE:" << c->exit_code() << std::endl;
if(ec) return; //app probably exit
// Do something with buffer and re-schedule
schedule_read();
}
int main() {
bp::child c("my_program_url", bp::std_out > in_pipe);
any_c = &c;
schedule_read();
io.run();
}
回答1:
Since you only run the io_service::run()
on the main thread, all completion handlers also run there. There's no threading.
Remember to pass the io_service to the child, and use the on_exit
handler:
Live On Coliru
#include <boost/process.hpp>
//#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <system_error>
#include <utility>
#include <iostream>
namespace bp = boost::process;
char my_buffer[1024];
boost::asio::io_service io;
bp::async_pipe in_pipe(io);
void handle_pipe_read(const boost::system::error_code &ec, std::size_t bytes_transferred);
void schedule_read() {
in_pipe.async_read_some(
boost::asio::buffer(my_buffer),
boost::bind(&handle_pipe_read, _1, _2));
}
void handle_pipe_read(const boost::system::error_code &ec, std::size_t bytes_transferred) {
if (ec)
return; // app probably exit
// Do something with buffer and re-schedule
std::cout.write(my_buffer, bytes_transferred);
if (in_pipe.is_open())
schedule_read();
}
int main() {
bp::child c("/bin/ls", bp::std_out > in_pipe,
bp::on_exit([](int code, std::error_code ec) {
std::cout << "Child exited (" << code << "): " << ec.message() << std::endl;
in_pipe.close();
}), io);
schedule_read();
io.run();
std::cout << "Service done (" << c.exit_code() << ")" << std::endl;
}
Prints:
a.out
main.cpp
Child exited (0): Success
Service done (0)
回答2:
The only solution that worked for me is the following
- schedule a completion read
- always check calling
child::running()
- on error_code set don't reschedule
When the pipe gets broken (because of a crash) the completion handler for a read has the boost::error_code argument set to true. Despite this I've seen cases where child::running() is false also when boost::error_code is NOT set.
来源:https://stackoverflow.com/questions/47653596/boost-process-running-and-exit-code-thread-safety