Блокировка сигналов приводит к тому, что процесс наддува не работает - PullRequest
0 голосов
/ 12 октября 2018

В приведенном ниже коде класс 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();
}

Пожалуйста, предложите, как я могу закрыть программу, используя поток обработки сигналов, а также заставить программу работать правильно.

1 Ответ

0 голосов
/ 12 октября 2018

Подумав об этом больше, я предлагаю блокировать только те сигналы, которые вы намерены обработать этим сигнальным потоком, например SIGINT и 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);
        // ...
});
...