定时器实现过程遇到的问题

原文转自:http://www.tanjp.com/archives/203 (即时修正和更新)

 

定时器实现过程遇到的问题

在服务端的程序里,时间是一个很常用,几乎无处不在的变量。如果不正确使用时间,将会导致灾难性的数据错误。所以,正确使用时间非常重要!

怎样才算是正确使用时间?

首先,我们得知道在程序世界里面,时间有哪些值?

1、协调世界时,又称世界统一时间,世界标准时间,国际协调时间,简称UTC。世界默认以格林威治时间(GMT)为准。

2、世界各个地区时区的时间。如北京时间GMT+8,就是格林威治时间加8小时。

3、以计算机CPU时钟结合程序启动的时间算出的时间戳。

4、时间轮算法每次tick算出的时间。

 

然后,如何算是正确使用时间?那得先想想,怎样是不正确的?

1、有一种唯一ID生成算法依赖于时间戳,如果时间改小了,就可能导致唯一ID重复,那可就是灾难性的逻辑错误。

2、有些依赖于系统日期时间的定时器检测,当系统时间由于某种原因导致时间回退到以前,那将会导致定时器卡死等待。甚至,std::this_thread:sleep_for 也是有BUG的,回退时间会导致该函数挂起等待,与期待的效果相违背。

3、有些时间校验的算法,如果就在那一瞬间,时间回退了,导致某个非法校验通过了?那也导致错误。

正确使用时间,应该保证时间戳在程序运行过程总是单调递增,这隐患两个意思,保持递增,不能停下,不能倒退。

 

最后,总结一下时间和定时器的问题。

1、把时间戳划分为三种:系统日期时间戳(system time),CPU时钟时间戳(cpu time),时间轮执行后的时间戳(tw time)。

2、底层逻辑相关的必须用CPU时钟时间戳(cpu time),如网络心跳,超时检测,唯一ID算法,等等。

3、业务逻辑层使用时间轮时间戳(tw time)的话,要有一套自动同步机制,保证与CPU时钟时间戳(cpu time)单调递增同步。

4、在进程启动前,尽可能保证各个机器的系统时间戳已同步。

5、在测试时间相关功能时,停掉3中所说的同步机制,通过指令加快时间轮时间戳(tw time),可达到改时间测试的效果。但不能把时间回退来测试。

 

踩过的坑

1、std::this_thread:sleep_for 有BUG,改变系统日期时间会导致 std::this_thread:sleep_for 卡住。改用 boost::this_thread:sleep_for 替代。

2、定时器如果依赖于系统日期时间,很可能由于时间同步问题或者手动改时间导致定时器卡死。

3、唯一ID生成算法依赖于时间,所以要采用CPU时钟作为统计的依据,保证时间只会单调递增。

4、boost::asio::deadline_timer 改变系统的日期时间,会导致定时器卡住,改用 boost::asio::steady_timer 替代。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章