[求助] ACE_High_Res_Timer的问题,用了后定时器会不准
我程序里有个600秒的定时器,实际执行时却是8分20秒的间隔。如果把程序初始化时调用的下面这行删除掉定时器就准了,为啥?
ACE_Reactor::instance()->timer_queue()->gettimeofday(&ACE_High_Res_Timer::gettimeofday_hr);
我使用ACE_High_Res_Timer的目的主要是避免系统时间变动对程序的运行造成影响。 顶一下,比较奇怪的问题,都不知道怎么判断原因所在。。。
代码中基本只用schedule_timer和cancel_timer。 经过测试,没有发现你说的情况,测试代码如下:
#include "ace/Timer_Queue.h"
#include "ace/Reactor.h"
#include "ace/High_Res_Timer.h"
#include "ace/Trace.h"
#include "ace/Recursive_Thread_Mutex.h"
#include "ace/Log_Msg.h"
ACE_Time_Value g_begin_time, g_end_time;
class CTimerHrTest: public ACE_Event_Handler
{
public:
int open()
{
ACE_Time_Value timer_interval(600);
m_timer_id = ACE_Reactor::instance ()->schedule_timer(this, 0, timer_interval, timer_interval);
g_begin_time = ACE_OS::gettimeofday();
ACE_Time_Value tm = ACE_High_Res_Timer::gettimeofday_hr();
ACE_DEBUG((LM_DEBUG, ACE_TEXT("begin absolute timer: %d\n"), g_begin_time.sec()));
ACE_DEBUG((LM_DEBUG, ACE_TEXT("begin tick timer: %d\n"), tm.sec() ));
if ( m_timer_id == -1 )
{
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "schedule_timer failed."),-1);
}
return 0;
}
virtual int handle_timeout(const ACE_Time_Value &tm, const void *)
{
// ACE_Time_Value tmp = tm - g_begin_time;
g_end_time = ACE_OS::gettimeofday();
ACE_DEBUG((LM_DEBUG, ACE_TEXT("end absolute timer: %d\n"),
(g_end_time.sec() - g_begin_time.sec()) ));
ACE_DEBUG((LM_DEBUG, ACE_TEXT("end tick timer: %d\n"), tm.sec() ));
return 0;
}
virtual int handle_close()
{
ACE_Reactor::instance ()->cancel_timer(m_timer_id);
delete this;
return 0;
}
private:
long m_timer_id;
};
int ACE_TMAIN(int argc, ACE_TCHAR **argv)
{
ACE_High_Res_Timer::global_scale_factor ();
// test timer source
ACE_Reactor::instance()->timer_queue()->gettimeofday(&ACE_High_Res_Timer::gettimeofday_hr);
CTimerHrTest timer_test;
if ( timer_test.open() == -1 )
{
ACE_DEBUG(( LM_DEBUG, ACE_TEXT("(%t) Timer_open failed\n") ));
return -1;
}
ACE_Reactor::instance()->run_event_loop();
}
测试结果: (Linux AS 4u5)
begin absolute timer: 1231479901
begin tick timer: 170079
end absolute timer: 600
end tick timer: 170679
回复 #3 dwh0403 的帖子
试了一下你的代码:begin absolute timer: 1231819410
begin tick timer: 92338
end absolute timer: 600
end tick timer: 93054
end absolute timer: 1085
end tick timer: 93631
end absolute timer: 1591
end tick timer: 94236
end absolute timer: 2094
end tick timer: 94835
。。。奇怪了,从absolute timer来看,和我说的8分多钟差不多,但那个tick timer看上去倒是600左右
[ 本帖最后由 Youth 于 2009-1-13 12:46 编辑 ]
又运行了一次,可重复性挺好
begin absolute timer: 1231822038begin tick timer: 95473
end absolute timer: 600
end tick timer: 96188
end absolute timer: 1085
end tick timer: 96766
end absolute timer: 1592
end tick timer: 97371
end absolute timer: 2094
end tick timer: 97969 继续顶。。。补充一下我的开发环境了:win xp sp3, vc8sp1, ace 5.6.1 大半年后再来顶一次,本来已经放下这个问题了,最新发现:
2台双核笔记本上有问题。
2台单核超线程台式机上没问题。
是我用法不对吗? ACE_High_Res_Timer是根据cpu的tick来计算的
双核的有问题,单核没问题,可能跟cpu或者os的tick计算方法有关。
很可能是ACE考虑的还不够全面。跟一下源码吧,应该不复杂。 这个问题我也遇到了,
为了解决系统时钟调整之后定时器的延时响应的问题,
引入了高精度定时器。结果测试却发现,
双核机器上导致ACE提供的定时器时钟不准的问题。
尝试使用单线程运行定时器,并设置到一个CPU上运行,效果也不甚理想。
有时间的话是得看看源代码实现,或者看看新版本是否有解决这个问题。 正好我也遇到这样的一个问题。。
看了下代码,在win32下是用BOOL QueryPerformanceCounter( LARGE_INTEGER *lpFrequency );来计算当前时间的。猜测是这个函数在多核情况下不准确。
整理简洁后的代码流程大致如下:
ACE_OS::gethrtime (const ACE_HRTimer_Op op)
{
ACE_UNUSED_ARG(op);
LARGE_INTEGER freq;
::QueryPerformanceCounter (&freq);
return freq.QuadPart;
}
ACE_INLINE void
ACE_High_Res_Timer::hrtime_to_tv (ACE_Time_Value &tv,
const ACE_hrtime_t hrt)
{
tv.sec ((long) (hrt / 1000000 ));
ACE_hrtime_t tmp = tv.sec ();
tmp *= (1000000 );
tv.usec ((long) (hrt - tmp));
}
ACE_INLINE ACE_Time_Value
ACE_High_Res_Timer::gettimeofday (const ACE_OS::ACE_HRTimer_Op op)
{
ACE_Time_Value tv;
ACE_High_Res_Timer::hrtime_to_tv (tv, ACE_OS::gethrtime (op));
return tv;
}
[ 本帖最后由 wishel 于 2009-12-31 17:04 编辑 ]