跟我学C++中级篇——定时器的设计

发布于:2025-03-01 ⋅ 阅读:(8) ⋅ 点赞:(0)

一、定时器

谈到定时器,理论上讲是各种语言和各种设计都无法避开的一个技术点。对于定时器来说,表面上就是一种时间间隔的处理约定,但对程序来说,可能就是设计层面、接口层面和库或框架以及系统应用的一个大集合。不同的系统,不同的库,不同的框架都或直接或间接的提供了各种实现定时器的方法。
而定时器的应用在软件层面上又是各种各样,有执行定时任务的,有执行到期任务的,有执行休眠的,反正定时器在稍微大一些程序中几乎是到处可见。可能有的程序中开发者看不到定时器,但不代表没用到。
定时器在应用上是一个非常关键的技术,大到航空航天,小到手机中的闹钟,都是定时器大显身手的地方。定时器不光可以一个单独使用,也可以N个一起使用,比如在前面提到的muduo库的定时器轮,就是一个非常典型的例子。

二、定时器实现的底层机制

定时器的底层实现,在硬件层面一般是通过类似晶振这种固定频率的硬件来提供基础的时间点,然后通过不同的手段得到不同的时间间隔。这里提到的底层实现机制不是指上面提到的硬件底层,一般指的操作系统的接口层、库和框架的实现。下面就常见的定时器的实现进行说明:
1、Windows系统
Windows平台上提供了API接口实现定时器,如常见的SetTimer等和timeSetEvent(多媒体定时器)。前者通过生成定时器并通过WM_TIEMR发送定时消息,所以其精度一般不会多高。而后者是一个依赖于硬件的类似计数的控制,利用回调函数来处理任务。在Windows的接口中还有一些其它的定时器处理接口,有兴趣可以翻看一下。
2、Linux系统
系统提供了类似Windows平台的setitimer定时器和高精度定时器。前者是调用内核中的定时器队列,后者直接调用硬件处理。
3、API封装使用
利用API封装的可就多了,比如常见的针对timerfd的调用的select(),poll(),epoll()函数等,它们的机制与这些接口在内核中的调用相关密切相联。
4、库或框架
标准库在C++11后提供了std::chrono相关的时间处理接口,可以通过sleep_for或sleep_until再配合多线程及其它相关的手段实现定时器功能。这个在一些框架中经常可以看到。有兴趣可以看看Boost或者Abseil、Folly等有名的库的相关实现,一定会受益匪浅。

另外,此处没有对类似Sleep等这种简单的定时应用接口进行说明,毕竟这个太简单了。

三、定时器的设计与开发

通过对开源的定时器以及相关接口的文档中的例程基本上可以看到定时器实现的处理逻辑及设计流程:
1、对外设计
a)提供定时设置接口,最典型的就是时钟间隔的设置接口
b)时钟回调的处理,主要是通过回调函数实现定时任务的工作
c)资源的管理,即是否回收相关的句柄等资源,比如在主动关闭定时器时,需要回收相关的句柄
2、内部设计
a)各种定时器底层功能的实现(定时,到时等等)以及任务队列、事件机制等
b)并行或并发的控制,保证在多线程的环境中能安全使用(当然,不考虑这种情况可以不进行处理)
c)错误和异常的控制,包括调试信息等。当在出现异常或错误时能向外提供友好的说明并尽可能不出现资源问题。当然,能自己恢复就更好了。
d)在性能要求更高的平台上,需要考虑对CPU或核心的占用效率及延时导致的自动补偿机制,还有任务调度产生的时间精度损失问题等
定时器的开发中会应用到很多技术,包括并行和并发技术,包括多线程的创建、管理,线程间的同步控制以及异常处理机制等。同时,在具体的实现过程中,还可以引入更多的新的技术,让定时器更准确更安全。所以可以看到不同时代或不同平台以及框架库中的实现都有很明显的不同。

四、总结

文章写得有点粗糙,主要是不知道如何有一个更好的切入点来分析定时器。不过也算对前面各种定时器的实现的一个笼统的概括,以后有机会再认真的综合整理一下。思考的不到位,有一种火候欠佳的感觉!


网站公告

今日签到

点亮在社区的每一天
去签到