Linux定时器

本文介绍了Linux下的定时器机制,包括睡眠函数、时钟处理和利用文件描述符的timerfd API。详细讨论了Linux为进程维护的三个计时器类型,并阐述了如何通过时间轮盘实现定期执行任务,通过任务队列和时间间隔管理来确保任务的精确执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux定时器

1. 睡眠函数

Linux下有两个睡眠函数,

#include <unistd.h>

unsigned int sleep(unsigned int seconds);

int usleep(useconds_t usec);

unsigned int alarm(unsigned int seconds);
1.seconds秒后触发一个SIGALRM信号,具体操作需要在信号处理函数中完成
2.seconds设置为0,则所有正在等待的alarm全部被取消
3.alarm和settimer共享共一个定时器,调用一个会影响到另一个
4.alarm创造的Alarms可以被Execve保留但是不会被fork产生的子进程继承
5.sleep的实现可能会用到SIGALRM,因此混用alarm与sleep会导致错误

2. 时钟处理

+ Linux为每个进程维护3个计时器,分别是,

  1. 真实计时器 计算程序运行的实际时间 发送SIGALRM 信号

  2. 虚拟计时器 计算的时程序运行在用户态时所消耗的时间,实际时间减去系统调用和程序睡眠所消耗的时间 发送SIGVTALRAM 信号

  3. 实用计时器 程序处于用户态和处于内核态所消耗的时间之和 发送SIGPROF信号

    用指定的初始间隔和重复间隔时间为进程设定好一个计时器后,该计时器就会定时的向进程发送时钟信号。·

  • 函数和数据结构

    #include <signal.h>
    #include <time.h>
    链接指令 -lrt
    int timer_create(clockid_t clockid, struct sigevent *sevp,
                            timer_t *timerid);
    创建一个新的进程内部的定时器变量,定时器id使用timerid返回,因此timerfd不能为空指针,该id在进程内唯一。clockid参数可以被设置为以下值:
    CLOCK_REALTIME
    CLOCK_MOONOTONIC
    CLOCK_PROCESS_CPUTIME_ID
    CLOCK_THREAD_CPUTIME_ID
    CLOCK_BOOTTIME
    CLOCK_REALTIME_ALARM
    CLOCK_BOOTTIME_ALARM   
        
    #include <sys/time.h>
    1.//获取计时器的设置
    int getitimer(int which, struct itimerval *curr_value);	
    2.//设置计时器
    int setitimer(int which, const struct itimerval *new_value,
                         	 struct itimerval *old_value); 
    
               struct itimerval {
                 struct timeval it_interval; /* Interval for periodic timer */
                   struct timeval it_value;    /* Time until next expiration */
               };
    
               struct timeval {
                   time_t      tv_sec;         /* seconds */
                   suseconds_t tv_usec;        /* microseconds */
               };
    参数which指定哪个计时器,可选项为
    ITIMER_REAL(真实计时器)ITIMER_VIRTUAL(虚拟计时器、
    ITIMER_PROF(实用计时器)

    3. 利用文件描述符进行通知的定时器:timerfd API

    #include <sys/timerfd.h>
    
    int timerfd_create(int clockid, int flags);
    clockid 可以被设置为
          	CLOCK_REALTIME	相对时间,从1970.1.1到目前的时间。更改系统时间 会更改获取的值,它以系统时间为坐标。
        	`CLOCK_MONOTONIC`绝对时间,获取的时间为系统重启到现在的时间,更改系统时间对齐没有影响。
    参数flags可以被设置为
        TFD_NONBLOCK(非阻塞)
    	TFD_CLOEXEC(同`O_CLOEXEC`)
    
    int timerfd_settime(int fd, int flags,
        		                		const struct itimerspec *new_value,
                               		  	struct itimerspec *old_value);
    
    int timerfd_gettime(int fd, struct itimerspec *curr_value);
    
    
             struct timespec {
                 	time_t tv_sec;                /* Seconds */
                    long   tv_nsec;               /* Nanoseconds */
             };
    
             struct itimerspec {
                   		struct timespec it_interval;  /* Interval for periodictimer */
                 		struct timespec it_value;     /* Initial expiration */
               };
    参数fd:  timerfd对应的文件描述符
    参数flag可被设置为 
        0 表示相对定时器
        TFD_TIMER_ABSTIME 表示是绝对定时器
    参数new_value:设置超时时间,如果为0,则表示停止定时器
    

参数old_value:一般设置为nullptr,如果不设置为nullptr则返回定时器此次之前设置的超时时间

这些系统调用通过文件描述符创建定时器并传递定时器到期通知,提供了对set_timer和timer_create的替代方案。好处是文件描述符可以被select\poll\epoll监控,相对信号控制方便很多。用法与timer的用法类似

  • 定时器类的C++封装

接口设计:

  1. 设定等待间隔和等待时间、开始计时,结束计时,以及计时到期后触发的时间
  2. 内部维护一个任务队列,定期执行任务队列中的任务。
  3. 为了让每个任务可以有自己的执行ll时间间隔,可以规定定时器管理类的间隔单位。
  4. 设置一个任务类,其中设置每个任务的执行间隔,距离下次执行任务剩余的时间间隔。
  5. 定时器管理类,每隔最小时间间隔单位去检查任务队列中的任务,如果其内部计时器小于等于0,则执行该任务,并将计时器归0.否则,在定时器上减去一个基本单位
  6. 为了管理任务队列中的数据,可以考虑增加一个待加入队列和待删除队列。
  7. 在每个基本时间间隔过期时,检查待加入任务队列和待删除任务队列。并将其中的任务加入/删除 任务队列

4. 时间轮盘 ->实现定期执行任务。

  1. 设置一个循环队列,其长度为定时器管理类的基本时间间隔总数,
  2. 设置一个指向队尾的指针,这个指针每秒移动一格,
  3. 链表中的每一个节点本身维护一个任务队列。
  4. 每次定时器到期后检查该时间节点的槽,如果槽内有任务。则将槽内的任务执行,并结合任务的执行间隔,将任务添加到下一个需要执行的时间节点
  5. 当前时间槽执行完毕后进行清空操作。继续执行下一个时间槽。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值