使用 boost::asio 实现事件计时器
Implementing an event timer using boost::asio
示例代码看起来很长,但实际上它并不那么复杂:-)
我想做的是,当用户调用 EventTimer.Start() 时,它将每 interval
毫秒执行一次回调处理程序(传入 ctor),持续 repeatCount
次。
你只需要看看函数 EventTimer::Stop()
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <ctime>
#include <sys/timeb.h>
#include <Windows.h>
std::string CurrentDateTimeTimestampMilliseconds() {
double ms = 0.0; // Milliseconds
struct timeb curtime;
ftime(&curtime);
ms = (double) (curtime.millitm);
char timestamp[128];
time_t now = time(NULL);
struct tm *tp = localtime(&now);
sprintf(timestamp, "%04d%02d%02d-%02d%02d%02d.%03.0f",
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec, ms);
return std::string(timestamp);
}
class EventTimer
{
public:
static const int kDefaultInterval = 1000;
static const int kMinInterval = 1;
static const int kDefaultRepeatCount = 1;
static const int kInfiniteRepeatCount = -1;
static const int kDefaultOffset = 10;
public:
typedef boost::function<void()> Handler;
EventTimer(Handler handler = NULL)
: interval(kDefaultInterval),
repeatCount(kDefaultRepeatCount),
handler(handler),
timer(io),
exeCount(-1)
{
}
virtual ~EventTimer()
{
}
void SetInterval(int value)
{
// if (value < 1)
// throw std::exception();
interval = value;
}
void SetRepeatCount(int value)
{
// if (value < 1)
// throw std::exception();
repeatCount = value;
}
bool Running() const
{
return exeCount >= 0;
}
void Start()
{
io.reset(); // I don't know why I have to put io.reset here,
// since it's already been called in Stop()
exeCount = 0;
timer.expires_from_now(boost::posix_time::milliseconds(interval));
timer.async_wait(boost::bind(&EventTimer::EventHandler, this));
io.run();
}
void Stop()
{
if (Running())
{
// How to reset everything when stop is called???
//io.stop();
timer.cancel();
io.reset();
exeCount = -1; // Reset
}
}
private:
virtual void EventHandler()
{
// Execute the requested operation
//if (handler != NULL)
// handler();
std::cout << CurrentDateTimeTimestampMilliseconds() << ": exeCount = " << exeCount + 1 << std::endl;
// Check if one more time of handler execution is required
if (repeatCount == kInfiniteRepeatCount || ++exeCount < repeatCount)
{
timer.expires_at(timer.expires_at() + boost::posix_time::milliseconds(interval));
timer.async_wait(boost::bind(&EventTimer::EventHandler, this));
}
else
{
Stop();
std::cout << CurrentDateTimeTimestampMilliseconds() << ": Stopped" << std::endl;
}
}
private:
int interval; // Milliseconds
int repeatCount; // Number of times to trigger the EventHandler
int exeCount; // Number of executed times
boost::asio::io_service io;
boost::asio::deadline_timer timer;
Handler handler;
};
int main()
{
EventTimer etimer;
etimer.SetInterval(1000);
etimer.SetRepeatCount(1);
std::cout << CurrentDateTimeTimestampMilliseconds() << ": Started" << std::endl;
etimer.Start();
// boost::thread thrd1(boost::bind(&EventTimer::Start, &etimer));
Sleep(3000); // Keep the main thread active
etimer.SetInterval(2000);
etimer.SetRepeatCount(1);
std::cout << CurrentDateTimeTimestampMilliseconds() << ": Started again" << std::endl;
etimer.Start();
// boost::thread thrd2(boost::bind(&EventTimer::Start, &etimer));
Sleep(5000); // Keep the main thread active
}
/* Current Output:
20110520-125506.781: Started
20110520-125507.781: exeCount = 1
20110520-125507.781: Stopped
20110520-125510.781: Started again
*/
/* Expected Output (timestamp might be slightly different with some offset)
20110520-125506.781: Started
20110520-125507.781: exeCount = 1
20110520-125507.781: Stopped
20110520-125510.781: Started again
20110520-125512.781: exeCount = 1
20110520-125512.781: Stopped
*/
我不知道为什么我第二次调用 EventTimer::Start() 根本不起作用。 我的问题是:
我应该在事件计时器::停止() 为了重置一切都是为了下次调用 Start() 会起作用吗?
还有什么需要修改的吗?
如果我使用另一个线程来启动 EventTimer::Start()(请参阅主函数中的注释代码),线程何时实际退出?
谢谢。
彼得
正如 Sam 所暗示的那样,根据你试图完成的任务,大多数时候停止io_service被认为是设计错误。您无需stop()
/reset()
io_service即可重新安排计时器。
通常,您会将线程或线程池附加到io_service
,然后您将使用io_service
安排所需的任何事件。io_service
机器就位后,由io_service
根据请求调度您的计划工作,然后您只需处理您与io_service
一起安排的事件或工作请求。
我并不完全清楚您要完成什么,但是您发布的代码中有一些不正确的地方。
-
io_service::reset()
只有在文档所述io_service::run()
的先前调用停止或工作耗尽后才应调用。 - 你不应该需要显式调用
Sleep()
,只要它有工作要做,对io_service::run()
的调用就会阻塞。
我想通了,但我不知道为什么我必须把io.reset()
放在Start()
中,因为它已经在 Stop() 中调用了。
请参阅帖子中的更新代码。
相关文章:
- Linux的Cpp上的计时器
- 提升 ASIO 无法识别计时器对象
- 提升 asio 并发计时器取消问题与链
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数
- 使用单体计时器的pthread_cond_timedwait有时会比预期晚超时
- 窗口中的微秒计时器
- 计时器是否从另一个线程启动?
- 如何在 c++ 中创建计时器
- C++回调计时器实现
- 在计时器或主线程外部的命令上销毁/替换线程
- OpenCL 基于事件的计时器(c++ 包装器)
- 开关(事件类型)不工作和计时器不显示
- 改进了 C++ 中计时器(超时事件)的实现
- MFC-在dll卸载时,扫描我的代码,任何剩余的计时器,事件,线程等
- 使用C++在windowsmetro中使用计时器触发事件
- 如何使用多个计时器来规划程序中的事件
- 高精度事件计时器
- 我的libevent计时器在另一个事件发生时立即停止.这正常吗?
- 如何使用C++ 11 创建计时器事件
- 使用 boost::asio 实现事件计时器