参考资料:
basic_waitable_timer::expires_after - 1.66.0 (boost.org)
#include <boost/asio.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
using namespace std;
#define PRINTF_NOW() \
do \
{ \
time_t timep; \
time(&timep); \
std::cout << "\033[31m" << __FUNCTION__ << "\033[0m" \
<< ",Time: " << ctime(&timep) << " "; \
} while (0)
class DataAccessor
{
private:
typedef boost::shared_ptr<boost::asio::system_timer> SystemTimerPtr;
boost::asio::io_context _context;
SystemTimerPtr _timer;
boost::uint64_t _t;
/* 数据 */
bool _running = false;
std::thread _saveThread; // 保存数据的线程
public:
~DataAccessor()
{
_context.stop();
PRINTF_NOW();
_saveThread.join();
}
void setTimer(boost::uint64_t t)
{
PRINTF_NOW();
_t = t;
if (!_running)
{
_timer =
boost::make_shared<boost::asio::system_timer>(_context, std::chrono::seconds(_t));
std::cout << "_t = " << _t << std::endl;
_timer->async_wait(boost::bind(&DataAccessor::handler, this, boost::placeholders::_1));
} else
{
std::size_t n = _timer->expires_after(std::chrono::seconds(_t));
// _timer->cancel_one();
std::cout << __FUNCTION__ << " " << n << " asynchronous operations were cancelled."
<< std::endl;
_timer->async_wait(boost::bind(&DataAccessor::handler, this, boost::placeholders::_1));
}
}
void run()
{
PRINTF_NOW();
if (_running)
{
return;
}
_running = true;
std::thread th([&]() {
try
{
auto cnt = _context.run();
std::cout << "cnt: " << cnt << std::endl;
} catch (const std::exception& ex)
{
std::cerr << "DataAccessor run failed.." << std::endl;
}
});
_saveThread.swap(th);
}
void handler(const boost::system::error_code& ec)
{
PRINTF_NOW();
if (!ec)
{ // 重启定时器
cout << "TimeOut: " << _t << endl;
std::size_t n = _timer->expires_after(std::chrono::seconds(_t));
std::cout << __FUNCTION__ << " " << n << " asynchronous operations were cancelled."
<< std::endl;
_timer->async_wait(boost::bind(&DataAccessor::handler, this, boost::placeholders::_1));
}
}
};
int main()
{
DataAccessor da;
da.setTimer(3);
da.run();
this_thread::sleep_for(chrono::seconds(10));
da.setTimer(4);
this_thread::sleep_for(chrono::seconds(10));
}
运行结果:
setTimer,Time: Tue Mar 12 14:00:31 2024
_t = 3
run,Time: Tue Mar 12 14:00:31 2024
handler,Time: Tue Mar 12 14:00:34 2024
TimeOut: 3
handler 0 asynchronous operations were cancelled.
handler,Time: Tue Mar 12 14:00:37 2024
TimeOut: 3
handler 0 asynchronous operations were cancelled.
handler,Time: Tue Mar 12 14:00:40 2024
TimeOut: 3
handler 0 asynchronous operations were cancelled.
setTimer,Time: Tue Mar 12 14:00:41 2024
setTimer 1 asynchronous operations were cancelled.
handler,Time: Tue Mar 12 14:00:41 2024
handler,Time: Tue Mar 12 14:00:45 2024
TimeOut: 4
handler 0 asynchronous operations were cancelled.
handler,Time: Tue Mar 12 14:00:49 2024
TimeOut: 4
handler 0 asynchronous operations were cancelled.
~DataAccessor,Time: cnt: 6
Tue Mar 12 14:00:51 2024
对于每次调用 async_wait()
,提供的处理程序将被调用一次。该处理程序将在以下情况下被调用:
- 计时器已过期;
- 计时器被取消,在这种情况下,处理程序将传递错误代码。
第 10 s setTimer
调用 expires_after
函数, 重新设置定时到期时间。同时取消的 1 个异步等待操作。可以看到,在第二次设置定时器超时时间时,原来的计时器被取消,handler 被立即调用,且错误码不为 0。
context 调用 stop()
时,handler 不会被调用。