Остановка запланированного задания с помощью SIGINT

Фон

Я пытаюсь остановить периодические задачи, когда пользователь прерывает процесс с помощью SIGINT. Я основал свой периодический планировщик задач на этот ответ.

Для этого я попытался передать указатель экземпляра 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

Решение

Конечно, я бы предложил использовать 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

Самое приятное то, что он изолирует вас от некоторых специфичных для платформы вещей и устраняет распространенные ошибки, связанные с написанием асинхронно-безопасных обработчиков.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]