linux应用开发闹钟,Linux应用开发中的定时器

什么是定时器

定时器,顾名思义就是用来定时的,通俗的可以将其看作一个闹钟。在Linux应用编程层上,当需要实现下列几种功能时,可考虑使用定时器。1.周期性执行某一项任务;

2.在指定时间去执行某一项任务;

定时功能的API

sleep()

usleep()

nanosleep()

alarm()

sleep()和usleep(),Linux并没有提供系统调用,他们都是在库函数中实现的,是通过调用alarm()来设定报警时间,调用sigsuspend()将进程挂起在信号SIGALARM上。sleep()精度是1秒,usleep()精度是1微妙;使用这种方法缺点比较明显,在Linux系统中,sleep类函数不能保证精度,尤其在系统负载比较大时,一般都会有超时现象。

nanosleep()则是Linux中的系统调用,它是使用定时器来实现的,该函数使调用进程睡眠;

alarm()也是通过定时器实现的,其精度只精确到秒级,它设置的定时器执行函数是在指定时间向当前进程发送SIGALRM信号。

间隔定时器

间隔定时器(Interval Timer,简称itimer)是指定时器采用“间隔”值(interval)来作为计时方式,当定时器启动后,间隔值interval将不断减小。当interval值减到0时,说明该间隔定时器到期。

间隔定时器主要被应用在用户进程上。每个Linux进程都有三个相互关联的间隔定时器:真实间隔定时器(ITIMER_REAL-以系统真实的时间计算):这种间隔定时器在启动后,不管进程是否运行,每个时钟滴答都将其间隔计数器减1。当减到0值时,内核向进程发送SIGALRM信号。

虚拟间隔定时器(ITIMER_VIRT-以该进程在用户态下花费的时间来计算):也称为进程的用户态间隔定时器。当虚拟间隔定时器启动后,只有当进程在用户态下运行时,一次时钟滴答才能使间隔计数器当前值it_virt_value减1。当减到0值时,内核向进程发送SIGVTALRM信号(虚拟闹钟信号),并将it_virt_value重置为初值it_virt_incr。

PROF间隔定时器(ITIMER_PROF-以该进程在用户态下和内核态下所费的时间来计算):当一个进程的PROF间隔定时器启动后,则只要该进程处于运行中,而不管是在用户态或核心态下执行,每个时钟滴答都使间隔计数器it_prof_value值减1。当减到0值时,内核向进程发送SIGPROF信号,并将it_prof_value重置为初值it_prof_incr。

POSIX定时器

POSIX定时器的是为了解决间隔定时器itimer的以下问题:一个进程同一时刻只能有一个同一种类型(ITIMER_REAL, ITIMER_PROF, ITIMER_VIRT)的itimer。POSIX定时器在一个进程中可以创建任意多个timer。

itimer定时器到期后,只能通过信号(SIGALRM,SIGVTALRM,SIGPROF)的方式通知进程,POSIX定时器到期后不仅可以通过信号进行通知,还可以使用自定义信号,还可以通过启动一个线程来进行通知。

itimer支持us级别,POSIX定时器支持ns级别。

号称最强大的定时器接口来自POSIX时钟系列。

int timer_create(clockid_t clockid, struct sigevent *sevp,timer_t timerid);

int timer_delete (timer_t timerid);

int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);

int timer_gettime(timer_t timerid, struct itimerspec *curr_value);

int timer_getoverrun(timer_t timerid);

timer_create()函数

第一个参数clockid的取值有四种,如下表

Clock ID描述

CLOCK_REALTIMESettable system-wide real-time clock

CLOCK_MONOTONICNonsettable monotonic clock

CLOCK_PROCESS_CPUTIME_IDPer-process CPU-time clock

CLOCK_THREAD_CPUTIME_IDPer-thread CPU-time clock

CLOCK_REALTIME 时间是系统保存的时间,即可以由 date 命令显示的时间,该时间可以重新设置。比如当前时间为上午 10 点 10 分,Timer 打算在 10 分钟后到时。假如 5 分钟后,我用 date 命令修改当前时间为 10 点 10 分,那么 Timer 还会再等十分钟到期,因此实际上 Timer 等待了 15 分钟。假如您希望无论任何人如何修改系统时间,Timer 都严格按照 10 分钟的周期进行触发,那么就可以使用 CLOCK_MONOTONIC。

CLOCK_PROCESS_CPUTIME_ID 的含义与 setitimer 的 ITIMER_VIRTUAL 类似。计时器只记录当前进程所实际花费的时间;比如还是上面的例子,假设系统非常繁忙,当前进程只能获得 50%的 CPU 时间,为了让进程真正地运行 10 分钟,应该到 10 点 30 分才允许 Timer 到期。

CLOCK_THREAD_CPUTIME_ID 以线程为计时实体,当前进程中的某个线程真正地运行了一定时间才触发 Timer。

第二个参数 struct sigevent 用来设置定时器到时时的通知方式。该数据结构如下:

struct sigevent {

int sigev_notify; /* Notification method */

int sigev_signo; /* Notification signal */

union sigval sigev_value; /* Data passed with notification */

void (*sigev_notify_function) (union sigval);

/* Function used for thread notification (SIGEV_THREAD) */

void *sigev_notify_attributes;

/* Attributes for notification thread (SIGEV_THREAD) */

pid_t sigev_notify_thread_id;

/* ID of thread to signal (SIGEV_THREAD_ID) */

};

sigev_notify 表示通知方式,有如下几种:

通知方式描述

SIGEV_NONE定时器到期时不产生通知

SIGEV_SIGNAL定时器到期时将给进程投递一个信号,sigev_signo 可以用来指定使用什么信号

SIGEV_THREAD定时器到期时将启动新的线程进行需要的处理

SIGEV_THREAD_ID(仅针对 Linux)定时器到期时将向指定线程发送信号

如果采用 SIGEV_NONE 方式,使用者必须调用timer_gettime()函数主动读取定时器已经走过的时间,类似轮询方式。

如果采用 SIGEV_SIGNAL 方式,使用者可以选择使用什么信号,用 sigev_signo 表示信号值,比如 SIG_ALARM。

如果使用 SIGEV_THREAD 方式,则需要设置 sigev_notify_function,当 Timer 到期时,将使用该函数作为入口启动一个线程来处理信号。sigev_value 保存了传入 sigev_notify_function 的参数。sigev_notify_attributes 如果非空,则应该是一个指向 pthread_attr_t 的指针,用来设置线程的属性(比如 stack 大小,detach 状态等)。

SIGEV_THREAD_ID 通常和 SIGEV_SIGNAL 联合使用,这样当 Timer 到期时,系统会向由 sigev_notify_thread_id 指定的线程发送信号,否则可能进程中的任意线程都可能收到该信号。这个选项是 Linux 对 POSIX 标准的扩展,目前主要是 GLibc 在实现 SIGEV_THREAD 的时候使用到,应用程序很少会需要用到这种模式。

sigev_signo在sigev_notify = SIGEV_SIGNAL 时使用,指定信号的种别(number)。

sigev_value在sigev_notify = SIGEV_THREAD 时使用,作为sigev_notify_function 的参数。union sigval的结构体如下:

union sigval

{

int sival_int;

void *sival_ptr;

};

(*sigev_notify_function)(union sigval)函数指针(指向通知执行函数),在sigev_notify = SIGEV_THREAD 时使用, 其他情况下置为NULL.

sigev_notify_attributes指向线程属性的指针,在sigev_notify = SIGEV_THREAD 时使用,指定创建线程的属性, 其他情况下置为NULL.

timer_settime()函数

第二个参数flags,flags取值只有2个 : 0 和 TIMER_ABSTIME。当 flags 为 0 时, new_value->it_value 表示希望timer首次到期时的时间与启动timer的时间间隔(例如,希望timer 在 2秒后到期)

当flags为 TIMER_ABSTIME 时, new_value->it_value 表示希望timer首次到期的绝对时间(例如希望timer 在 01:23:45 到期)

如果new_value->it_value 设定的绝对时间 早于 当前的绝对时间, 那么timer会立即到期.

如果时钟 CLOCK_REALTIME 被调整了,那么timer的首次过期时间也会适当调整.

第三个参数new_value的结构提如下,有2个子域: it_value 和 it_interval

struct itimerspec

{

struct timespec it_interval; /* Timer interval(timer循环时间间隔) */

struct timespec it_value; /* Initial expiration(timer初次到期时间间隔) */

};

it_value : 用于设置首次timer到期的时间, 也是 启动/停止 timer的控制域

it_interval : 用于设置timer循环的时间间隔, 如果其值不为0(秒和纳秒至少有一个不为0),每次timer到期时,timer会使用new_value->it_interval的值重新加载timer;

如果其值为0, timer只会在it_value指定的时间到期一次,之后不会重新加载timer.

启动timer

前提:timer处于停止(disarmed)状态,否则就是重置timer

设置:new_value->it_value的值是非0值(秒和纳秒都不等于0或者其中一个不等于0)

结果:timer变为启动(armed)状态.

停止timer

设置:new_value->it_value的的值为0(秒和纳秒都为0)

结果:timer变为停止(disarmed)状态.

重置timer

前提:timer处于已启动(armed)状态,否则就是启动timer

设置:new_value->it_value的的值不为0(秒和纳秒至少有一个不为0)

结果:timer仍为(armed)状态.之前的参数(即new_value(it_value 和 it_interval))设置会被覆盖.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值