1

在下面的代码中,该类Process可以boost process在异步模式下运行一个进程,如果超时可以终止它。现在为了关闭它,我阻塞了所有线程中的所有信号,并创建了一个特定的线程 signal_thread 来处理信号。这样做时,程序停止工作。我猜这可能是因为父进程无法再收到信号SIGCHLD并且知道子进程已经执行完毕。

#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();
}

请建议我如何使用信号处理线程关闭程序以及使程序正常工作。

4

1 回答 1

2

仔细考虑一下,我建议仅阻塞您打算让该信号线程处理的信号,例如SIGINTand 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);
        // ...
});
于 2018-10-12T08:15:15.380 回答