背景
当用户使用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...
,并且应用程序退出。
问题
我的方法正确吗?如何有效停止计划的任务并退出应用程序?
我错过了什么吗?
答案 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
最好的部分是使您与某些平台特定的事物隔离,并消除了与编写异步安全处理程序有关的常见陷阱。