问题
In the code below the class Process
can run a process using boost process
in asynchronous mode and can kill it if it times out. Now in order to shut it down, I block all the signals in all threads and create a specific thread signal_thread to handle signals. On doing this the program stops working. I guess this is probably because the parent process can no longer receive the signal SIGCHLD
and know that the child process has finished executing.
#include <iostream>
#include <csignal>
#include <thread>
#include <chrono>
#include <future>
#include <boost/process.hpp>
#include <boost/asio.hpp>
namespace bp = boost::process;
std::atomic<bool> stop(false);
class Process
{
public:
Process(const std::string& cmd, const int timeout);
void run();
private:
void timeoutHandler(const boost::system::error_code& ec);
void kill();
const std::string command;
const int timeout;
bool stopped;
boost::process::group group;
boost::asio::io_context ioc;
boost::asio::deadline_timer deadline_timer;
unsigned returnStatus;
};
Process::Process(const std::string& cmd, const int timeout):
command(cmd),
timeout(timeout),
stopped(false),
ioc(),
deadline_timer(ioc),
returnStatus(0)
{}
void Process::timeoutHandler(const boost::system::error_code& ec)
{
if (stopped || ec == boost::asio::error::operation_aborted)
{
return;
}
std::cout << "Time Up!" << std::endl;
kill();
deadline_timer.expires_at(boost::posix_time::pos_infin);
}
void Process::run()
{
std::future<std::string> dataOut;
std::future<std::string> dataErr;
std::cout << "Running command: "<< command << std::endl;
bp::child c(command, bp::std_in.close(),
bp::std_out > dataOut,
bp::std_err > dataErr, ioc,
group,
bp::on_exit([=](int e, const std::error_code& ec) {
std::cout << "on_exit: " << ec.message() << " -> "<< e << std::endl;
deadline_timer.cancel();
returnStatus = e;
}));
deadline_timer.expires_from_now(boost::posix_time::seconds(timeout));
deadline_timer.async_wait(std::bind(&Process::timeoutHandler, this, std::placeholders::_1));
ioc.run();
c.wait();
std::cout << "returnStatus "<< returnStatus << std::endl;
std::cout << "stdOut "<< dataOut.get() << std::endl;
std::cout << "stdErr "<< dataErr.get() << std::endl;
}
void Process::kill()
{
std::error_code ec;
group.terminate(ec);
if(ec)
{
std::cerr << "Error occurred while trying to kill the process: " << ec.message() << std::endl;
throw std::runtime_error(ec.message());
}
std::cout << "Killed the process and all its descendants" << std::endl;
stopped = true;
}
void myfunction()
{
while(true)
{
Process p("date", 3600);
p.run();
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
if(stop)
break;
}
}
int main() {
sigset_t sigset;
sigfillset(&sigset);
::pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
std::thread signal_thread([]() {
while(true)
{
sigset_t sigset;
sigfillset(&sigset);
int signo = ::sigwaitinfo(&sigset, nullptr);
if(-1 == signo)
std::abort();
std::cout << "Received signal " << signo << '\n';
if(signo != SIGCHLD)
{
break;
}
}
stop = true;
});
myfunction();
signal_thread.join();
}
Please suggest how I can shut down the program using the signal handling thread as well make the program work correctly.
回答1:
Thinking more about it, I suggest blocking only signals that you intend for that signal thread to handle, such as SIGINT
and SIGTERM
:
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
::pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
std::thread signal_thread([sigset]() { // Use the same sigset.
// ...
int signo = ::sigwaitinfo(&sigset, nullptr);
// ...
});
来源:https://stackoverflow.com/questions/52774591/blocking-signals-causes-boost-process-not-to-work