Opened 13 years ago
Last modified 6 years ago
#3504 reopened Feature Requests
deadline_timer (based on UTC time) is not suitable for communication timeouts
Reported by: | Owned by: | chris_kohlhoff | |
---|---|---|---|
Milestone: | To Be Determined | Component: | asio |
Version: | Boost 1.41.0 | Severity: | Problem |
Keywords: | Cc: | pgquiles@…, leon@… |
Description
If you use the deadline_timer to make a polling every 10th second, it will be heavely affected if someone adjust the system clock with date command, or if the time is adjusted automaticly by NTP.
Uses as this should use a timer that cannot make jumps like that.
I solved this by making a new time_traits called monotone_time. It uses GetTickCount() for windows and clock_gettime(CLOCK_MONOTONIC, ...) for linux. See attachment.
To use it your timer must be a monotone_timer instead of a deadline_timer. You can use both types of timers in you application.
I hope this can be a part of a future release of boost::asio
Attachments (7)
Change History (27)
by , 13 years ago
Attachment: | monotone_timer.hpp added |
---|
comment:1 by , 13 years ago
Cc: | added |
---|---|
Version: | Boost 1.38.0 → Boost 1.41.0 |
I can confirm Asio timers are broken if you set the date back/forward. The timer does not need to fire any fast, you can fire the timer just once a day and it will fail if you do this:
- Let's say the time now is 2009-11-23 13:45:20
- Start timer with deadline in 1 hour. Asio watches the system and will fire the timer at 2009-11-23 14:45:20.
- Set date back 1 day: 2009-11-22 13:45:20
- Timer never fires
While Bjarne's solution is good, the #ifdef for Linux is not. It should not check for Linux but for platforms where clock_gettime is available, which is done with "#if defined(_POSIX_TIMERS) && ( _POSIX_TIMERS > 0 ) && defined(_POSIX_MONOTONIC_CLOCK)".
I've fixed Bjarne's code and uploaded the attachment.
In addition to that, on Linux with glibc >= 2.11, linking with librt is required. Linux with glibc <= 2.9 does not need linking with librt but it does not do any harm, either. FreeBSD and Mac OS X do not need linking with librt.
follow-up: 6 comment:2 by , 13 years ago
There is static mutex in function 'now' on windows. If there r lots of connection which own monotone_timer, ther will be execute one by one because this static mutex. I fixed the code and unploaded the attachment
comment:3 by , 13 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
I agree with the need for a monotonic timer. However, I consider the provision of a monotonic clock to be out of scope for asio. The date_time library might be better. Alternatively, once c++0x library implementations are available we may use those. Once a monotonic clock is available I will look at adding a monotonic_timer to asio.
comment:4 by , 13 years ago
Resolution: | wontfix |
---|---|
Status: | closed → reopened |
Let me disagree. Timers are implemented in asio, not in date_time. Even if only for coherence (other timers are implemented in asio not in date_time), it makes no sense at all to implement the monotonic timer in date_time instead of asio. Please, reconsider your position.
comment:5 by , 13 years ago
Resolution: | → wontfix |
---|---|
Status: | reopened → closed |
Let me restate:
- Yes, a monotonic_timer would be a good addition to asio. Asio is the right place for this.
- A monotonic clock is a prerequisite for a monotonic_timer.
- The provision of a monotonic clock is out of scope for asio as far as I'm concerned. By clock, I mean the monotonic equivalent of boost::posix_time::microsec_clock::universal_time().
I hope that makes it clear.
comment:6 by , 13 years ago
Replying to victor:
There is static mutex in function 'now' on windows. If there r lots of connection which own monotone_timer, ther will be execute one by one because this static mutex. I fixed the code and unploaded the attachment
this version uses _ftime instead of GetTickCount for windows. The original problem seems to return using any system time function other than GetTickCount ???
by , 13 years ago
Attachment: | monotone_timer.hpp-NO_MUTEX added |
---|
Removed need for mutex while maintaining monotonic functionality
follow-up: 8 comment:7 by , 13 years ago
I've looked into the QueryPerformanceXXXXX functions and it seems they may not be as accurate as I would like. While the GetTickCount version requires a mutex it may be better to suffer a possible small performance hit in order to maintain accuracy.
If anyone has any up to date knowledge of any issues with the QueryPerformanceXXXXX functions I would appreciate it.
comment:8 by , 13 years ago
Replying to anonymous:
I've looked into the QueryPerformanceXXXXX functions and it seems they may not be as accurate as I would like. While the GetTickCount version requires a mutex it may be better to suffer a possible small performance hit in order to maintain accuracy.
If anyone has any up to date knowledge of any issues with the QueryPerformanceXXXXX functions I would appreciate it.
In the past they have been a problem, especially on multi-core processors but MSDN assures us that QueryPerformanceFrequency will not change once the system has started.
http://msdn.microsoft.com/en-us/library/ms644905%28VS.85%29.aspx
comment:9 by , 12 years ago
I'm confused as to why this is "wontfix". As it stands, any change in the system time completely screws up any system relying on the deadline timer. If not for the files and ideas presented here I would have been lost.
You cannot use the system time for timers.
follow-ups: 12 15 comment:10 by , 12 years ago
I may be wrong, but I think the attached file "monotone_timer.hpp-NO_MUTEX" suffers from really bad roll over issues. Multiplying a rolling monotonic timer by a constant (1000000000/frequency.QuadPart on line 80) doesn't produce a valid monotonic nanosecond count.
I've attached the version I'm trying which keeps times and durations in terms of the performance counter (monotone_timer_better_rollover.cpp/.hpp).
You use it as: TimerImpl m_Timer; m_Timer.expires_from_now(TimerTraits::milliseconds_to_duration(milliseconds_delay));
I agree that this is a really big issue. I was hoping when we started using boost that we would be spending out time writing our application, not spending hours trying to get a basic timer working reliably.
I also think the documentation should be changed. The example provided (e.g. http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/timers/tick_count_timer.cpp) is *WRONG* and doesn't work as expected.
by , 12 years ago
Attachment: | monotone_timer_better_rollover.cpp added |
---|
by , 12 years ago
Attachment: | monotone_timer_better_rollover.hpp added |
---|
comment:11 by , 11 years ago
I'd like to resubmit this feature request now that boost::chrono::steady_clock is available on the release branch.
follow-up: 14 comment:12 by , 11 years ago
Replying to kjohnson@…:
I may be wrong, but I think the attached file "monotone_timer.hpp-NO_MUTEX" suffers from really bad roll over issues. Multiplying a rolling monotonic timer by a constant (1000000000/frequency.QuadPart on line 80) doesn't produce a valid monotonic nanosecond count.
I've attached the version I'm trying which keeps times and durations in terms of the performance counter (monotone_timer_better_rollover.cpp/.hpp).
You use it as: TimerImpl m_Timer; m_Timer.expires_from_now(TimerTraits::milliseconds_to_duration(milliseconds_delay));
Your attached code uses a header named CheckedInt64.h, could you add this as well please?
comment:13 by , 11 years ago
Cc: | added |
---|
comment:14 by , 11 years ago
It is just a class that performs 64-bit arithmetic with overflow checking. This is internal code that I would require permission to release - honestly I can't be bothered doing this. You can just replace it with normal 64-bit arithmetic if you want.
e.g.
boost::posix_time::time_duration TimerTraits::to_posix_duration(
const TimerTraits::duration_type& d)
{
return boost::posix_time::milliseconds(d.ticks_ * 1000 / performance_freq_);
}
Replying to anonymous:
Replying to kjohnson@…:
I may be wrong, but I think the attached file "monotone_timer.hpp-NO_MUTEX" suffers from really bad roll over issues. Multiplying a rolling monotonic timer by a constant (1000000000/frequency.QuadPart on line 80) doesn't produce a valid monotonic nanosecond count.
I've attached the version I'm trying which keeps times and durations in terms of the performance counter (monotone_timer_better_rollover.cpp/.hpp).
You use it as: TimerImpl m_Timer; m_Timer.expires_from_now(TimerTraits::milliseconds_to_duration(milliseconds_delay));
Your attached code uses a header named CheckedInt64.h, could you add this as well please?
follow-up: 16 comment:15 by , 11 years ago
Replying to kjohnson@…:
I may be wrong, but I think the attached file "monotone_timer.hpp-NO_MUTEX" suffers from really bad roll over issues. Multiplying a rolling monotonic timer by a constant (1000000000/frequency.QuadPart on line 80) doesn't produce a valid monotonic nanosecond count.
I'm investigating an issue I've had where timers have stopped firing. I used an implementation just like "monotone_timer.hpp-NO_MUTEX", and I was wanting to narrow down the cause of my problem.
Would it be possible to get a little more detail about why that equation doesn't "produce a valid monotonic nanosecond count"? I would really appreciate it.
comment:16 by , 11 years ago
Replying to Aaron_Wright@…:
Replying to kjohnson@…:
I may be wrong, but I think the attached file "monotone_timer.hpp-NO_MUTEX" suffers from really bad roll over issues. Multiplying a rolling monotonic timer by a constant (1000000000/frequency.QuadPart on line 80) doesn't produce a valid monotonic nanosecond count.
I'm investigating an issue I've had where timers have stopped firing. I used an implementation just like "monotone_timer.hpp-NO_MUTEX", and I was wanting to narrow down the cause of my problem.
Would it be possible to get a little more detail about why that equation doesn't "produce a valid monotonic nanosecond count"? I would really appreciate it.
I was wrong - it doesn't.
It is always true that:
((count+n)*ns_over_freq) - (count*ns_over_freq) = (n*ns_over_freq)
in the ring of unsigned 64-bit numbers - i.e. monotonic steps in the count always produce monotonic steps in the output - it just wraps around more often.
I was obviously a bit confused and frustrated that day.
I did warn you :)
There were a couple of fixes in 1.45 that you may be interested in.
https://svn.boost.org/trac/boost/ticket/4568
https://svn.boost.org/trac/boost/ticket/4745
I've moved off this now and probably can't help anymore.
by , 11 years ago
Attachment: | MonotonicDeadlineTimer.h added |
---|
monotonic_deadline_timer using boost::chrono::steady_clock
comment:17 by , 11 years ago
I've attached a header file that I recently implemented in our product that was suffering the same issue described in this thread. It provides a ready-to-use boost::asio::monotonic_deadline_timer class that is powered by the boost::chrono::steady_clock. So far in our testing adjusting the system clock forward or back no longer impacts when the timer fires. When you ask for, say, 10 seconds you always get 10 seconds. Hopefully this or something similar will appear in a future Boost version. Enjoy!
comment:18 by , 10 years ago
Any new plans to fix this or have a monotonic_dealine_timer officially included in Boost?
Also, I noticed a similar behavior using this_thread::sleep()
comment:19 by , 6 years ago
Component: | asio → xpressive |
---|---|
Milestone: | Boost 1.41.0 → Website 1.X |
Resolution: | wontfix |
Severity: | Problem → Not Applicable |
Status: | closed → reopened |
Type: | Feature Requests → Library Submissions |
Version: | Boost 1.41.0 → Boost.Build-M3 |
Hello! Do you use Twitter? I'd like to follow you if that would be okay. I'm undoubtedly enjoying your blog and look forward to new posts. dfcdefcffabedadc
comment:20 by , 6 years ago
Component: | xpressive → asio |
---|---|
Milestone: | Website 1.X → To Be Determined |
Severity: | Not Applicable → Problem |
Type: | Library Submissions → Feature Requests |
Version: | Boost.Build-M3 → Boost 1.41.0 |
Undid vandalism. I would like to take this opportunity to reiterate my request that deadline_timer be based on boost::chrono::steady_clock.
monotone_timer.hpp