使用SIGINT

时间:2018-12-05 12:33:31

标签: c++ c++11 boost-asio sigint

背景

当用户使用SIGINT中断进程时,我试图停止定期任务。我的定期任务计划程序基于this answer

为此,我尝试将PeriodicScheduler实例指针传递给我的InterruptHandler并调用ps->stop()

定期任务计划程序标题:

#ifndef __PERIODICSCHEDULER_H__
#define __PERIODICSCHEDULER_H__

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>

namespace APP{
    class PeriodicTask : boost::noncopyable {
        public:
            typedef std::function<void()> handler_fn;

            PeriodicTask(boost::asio::io_service& ioService
                , std::string const& name
                , int interval
                , handler_fn task);
            void execute(boost::system::error_code const& e);
            void start();

        private:
            void start_wait();

            boost::asio::io_service& ioService;
            boost::asio::deadline_timer timer;
            handler_fn task;
            std::string name;
            int interval;

    }; /* class PeriodicTask */

    class PeriodicScheduler : boost::noncopyable
    {
        public:
            template<typename T, typename... Args>
            std::unique_ptr<T> make_unique(Args&&... args) {
                return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
            }

            void run();
            void stop();
            void addTask(std::string const& name
                                            , PeriodicTask::handler_fn const& task
                                            , int interval);

        private:
            boost::asio::io_service io_service;
            std::vector<std::unique_ptr<PeriodicTask>> tasks;
    }; /* PeriodicScheduler */
} /* namespace Resto */

#endif /* __PERIODICSCHEDULER_H__ */

定期任务计划程序源:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>

#include "periodicScheduler.h"

APP::PeriodicTask::PeriodicTask(boost::asio::io_service& ioService
            , std::string const& name
            , int interval
            , handler_fn task)
            : ioService(ioService)
            , interval(interval)
            , task(task)
            , name(name)
            , timer(ioService){
            // Schedule start to be ran by the io_service
            ioService.post(boost::bind(&PeriodicTask::start, this));
        }

void APP::PeriodicTask::execute(boost::system::error_code const& e){
    if (e != boost::asio::error::operation_aborted) {

        task();

        timer.expires_at(timer.expires_at() + boost::posix_time::seconds(interval));
        start_wait();
    }
}

void APP::PeriodicTask::start(){

    // Uncomment if you want to call the handler on startup (i.e. at time 0)
    // task();

    timer.expires_from_now(boost::posix_time::seconds(interval));
    start_wait();
}

void APP::PeriodicTask::start_wait(){
    timer.async_wait(boost::bind(&PeriodicTask::execute
        , this
        , boost::asio::placeholders::error));
}



void APP::PeriodicScheduler::run(){
    io_service.run();
}

void APP::PeriodicScheduler::stop(){
    io_service.stop();
}

void APP::PeriodicScheduler::addTask(std::string const& name
    , PeriodicTask::handler_fn const& task
    , int interval){
    tasks.push_back(make_unique<PeriodicTask>(std::ref(io_service)
        , name, interval, task));
}

以下是InterruptHandler:

#include <csignal>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <boost/asio.hpp>

#include "periodicScheduler.h"

static std::condition_variable _condition;
static std::mutex _mutex;

namespace APP {
    class InterruptHandler {
    public:
        static void hookSIGINT() {
            signal(SIGINT, handleUserInterrupt);        
        }

        static void handleUserInterrupt(int signal){
            if (signal == SIGINT) {
                std::cout << "SIGINT trapped ..." << '\n';
                _condition.notify_one();
            }
        }

        static void waitForUserInterrupt(APP::PeriodicScheduler *ps) {
            std::unique_lock<std::mutex> lock { _mutex };
            _condition.wait(lock);
            ps->stop();
            std::cout << "user has signaled to interrup program..." << '\n';
            lock.unlock();
        }
    };
}

我的main()

int main(int ac, const char * av[]) {

    InterruptHandler::hookSIGINT();

    APP::PeriodicScheduler ps;

    APP::WorkerClass wc;

    // WorkerClass::someTask and WorkerClass:someOtherTask are dummy functions only with sleep(5); inside them

    ps.addTask("someTask", boost::bind( &APP::WorkerClass::someTask, wc ), 60);
    ps.addTask("someOtherTask", boost::bind( &APP::WorkerClass::someOtherTask, wc ), 60);

    ps.run();

    InterruptHandler::waitForUserInterrupt(&ps);

    return 0;
}

问题

在终端中运行我的应用程序后,按CTRL + C触发中断。我可以在终端中看到SIGINT trapped ...,但是应用程序继续运行。

如果我注释掉ps.run();语句,则在按CTRL + C时,我会看到SIGINT trapped ...后跟user has signaled to interrup program...,并且应用程序退出。

问题

我的方法正确吗?如何有效停止计划的任务并退出应用程序?

我错过了什么吗?

1 个答案:

答案 0 :(得分:0)

无论如何,我建议使用signal_set https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/signal_set.html

以下是一些示例:https://stackoverflow.com/search?q=user%3A85371+signal_set

最好的部分是使您与某些平台特定的事物隔离,并消除了与编写异步安全处理程序有关的常见陷阱。