升压异步定时器不重置,不断被调用。

问题描述 投票:0回答:1

我的程序中有一个定时器,它必须根据两个条件执行报警:1.缓冲区大小达到OR2. 定时器过期。

我已经写好了我的函数,在缓冲区结束时,它调用。

timer.expires_from_now(interval);
timer.async_wait(boost::bind(&Database::setAlarm, this, _1));

其中,根据我的理解,我希望async_wait调用来重置定时器。

但实际情况是,一旦定时器启动,它就会在每一次的 interval (2秒),并触发报警,同时重置定时器。从本质上讲,我只想在定时器过期时调用警报,因为现在看起来发生的情况是定时器警报每隔一段时间就被调用一次,而不是过期。

所以基本上我想做的是(如果时间间隔是=2)。

t=1 buffer got value...
    timer reset
t=2 buffer got value...
    timer reset
t=3 no value...
    timer = 1 sec
t=4 no value
    timer = 2 sec
    trigger alarm
    timer reset

但现在的情况是:

t=1 buffer got value...
    trigger alarm
    timer reset
t=2 buffer got value...
    trigger alarm
    timer reset
t=3 no value...
    trigger alarm
    timer reset
t=4 no value
    timer = 2 sec
    trigger alarm
    timer reset

CODE

cpp

boost::shared_ptr<Database> Database::dbInstance;

Database::Database()
    : work(new io_service::work(io)), interval(2000), timer(io, interval) /* {}; */
{
    // std::cout << " CONSTRUCTED " << std::endl;
}

void Database::setAlarm(const boost::system::error_code& ec)
{
    std::cout << "[TEST] WE ARE IN SET ALARM - ec message = " << ec.message() << std::endl;
    std::cout << "[TEST] WE ARE IN SET ALARM - ec value   = " << ec.value() << std::endl;
    std::cout << "[TEST] WE ARE IN SET ALARM - ec         = " << ec << std::endl;

    DB_WRITE_TIME = 500; // 500 ms

    if(!ec) // success = 0, if !false
    {
        std::cout << " TIMER RESET " << std::endl;
        boost::posix_time::milliseconds interval(DB_WRITE_TIME);
        // timer.expires_at(timer.expires_at() + interval);
        timer.expires_from_now(interval);
        timer.async_wait(boost::bind(&Database::setAlarm, this, _1)); // RESET HERE
    }
}

int Database::buffer()
{
    // do buffer stuff

    // timer.expires_at(timer.expires_at() + interval);
    timer.expires_from_now(interval);
    timer.async_wait(boost::bind(&Database::setAlarm, this, _1)); // RESET HERE
    return 0;
}

头部

class Database
{
private:
    static boost::shared_ptr<Database> dbInstance;

public:
    typedef boost::asio::io_service io_service;
    io_service io;
    boost::scoped_ptr<io_service::work> work;
    boost::posix_time::milliseconds interval;
    boost::asio::deadline_timer timer;
    boost::thread timerThread;

    void run_io()
    {
        std::cout << "ENTER IO THREAD" << std::endl;
        io.run();
        std::cout << "LEAVE IO THREAD" << std::endl;
    }

public:
    static Database &getInstance()
    {
        if (!dbInstance)
        {
            std::cout << " INSTANCE CREATED " << std::endl;
            dbInstance.reset(new Database());
            dbInstance->timer.async_wait(boost::bind(&Database::setAlarm, dbInstance.get(), _1));
            dbInstance->timerThread = boost::thread(boost::bind(&Database::run_io,dbInstance));
        }
        return *dbInstance;
    }
};
c++ asynchronous boost timer boost-asio
1个回答
0
投票

你有一个无限循环,因为每次在完成处理程序中你都会启动新的异步任务。

void handler(err) {     <--------
    if (!err) {                 | handler calls handler
        async_wait(handler);  ---
    }
}

这有什么不清楚的地方吗?现在,你的应用程序工作得很好,就像你写的那样。

与其采用这种方法,你应该在你的类中添加另一个成员函数,它将在定时器过期时被调用。

void alarmDone(const boost::system::error_code& err) {
    if (!err) {
        // no pending tasks were cancelled 
        // interval elapsed, timer expired, alarm is done 
        std::cout << "Done, alarm triggered" << std::endl;

        // Dont initate here any new tasks 
    }
    else {
        // previous pending handler for [timer] cancelled 
    }
}

void setAlaram() {
    boost::posix_time::milliseconds interval(2000);

    timer.expires_from_now(interval);
    timer.async_wait( std::bind(&Database::alarmDone,this,std::placeholders::_1) );
}

你可以保留一个 setAlarm 作为一个例程来计划启动警报,并在它结束时进行处理。但是,你必须添加一些变量来控制何时可以启动一个新的任务。

void Database::setAlarm(const boost::system::error_code& ec)
{
    if(!ec) // success = 0, if !false
    {
        if (alaramStarted) {
            // ok alarm was fired, is done, don't start new async task 
            return;              // abort 
        }
        timer.expires_from_now(interval);
        timer.async_wait(boost::bind(&Database::setAlarm, this, _1)); // RESET HERE
        alarmStarted = true;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.