POSIX定时器Timer

 

POSIX Timer

间隔定时器 setitimer 有一些重要的缺点,POSIX Timer 对 setitimer 进行了增强,克服了 setitimer 的诸多问题:

  • 首先,一个进程同一时刻只能有一个 timer。假如应用需要同时维护多个 Interval 不同的计时器,必须自己写代码来维护。这非常不方便。使用 POSIX Timer,一个进程可以创建任意多个 Timer。
  • setitmer 计时器时间到达时,只能使用信号方式通知使用 timer 的进程,而 POSIX timer 可以有多种通知方式,比如信号,或者启动线程。
  • 使用 setitimer 时,通知信号的类别不能改变:SIGALARM,SIGPROF 等,而这些都是传统信号,而不是实时信号,因此有 timer overrun 的问题;而 POSIX Timer 则可以使用实时信号。

备注:通过kill –l可以查看系统支持的所有信号列表。编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

  • setimer 的精度是 ms,POSIX Timer 是针对有实时要求的应用所设计的,接口支持 ns 级别的时钟精度。
函数名功能描述
timer_create 创建一个新的 Timer;并且指定定时器到时通知机制
timer_delete删除一个 Timer
timer_gettimeGet the time remaining on a POSIX.1b interval timer
timer_settime开始或者停止某个定时器。
timer_getoverrun获取丢失的定时通知个数。

使用 Posix Timer 的基本流程很简单,首先创建一个 Timer。创建的时候可以指定该 Timer 的一些特性,比如 clock ID。clock ID 即 Timer 的种类,可以为下表中的任意一种:

POSIX Timer clock ID

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。

设置到期通知方式

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

结构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 表示通知方式,有如下几种:

POSIX Timer 到期通知方式

通知方式描述
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 的时候使用到,应用程序很少会需要用到这种模式。

————————————————
版权声明:本文为CSDN博主「许振坪」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/benkaoya/java/article/details/17342711

 

可以使用 POSIX 定时器的重复定时器功能来实现多次触发。具体方法如下: 1. 创建一个 POSIX 定时器,设置 timer_create() 函数的第三个参数为 TIMER_PERIODIC 表示创建一个重复定时器。 2. 设置定时器的初始值和间隔,可以使用 timer_settime() 函数来实现。 3. 在定时器触发时的回调函数中执行需要重复执行的操作。 4. 如果需要停止定时器,可以使用 timer_delete() 函数来删除定时器。 下面是一个简单的示例代码,每隔 1 秒输出一次 "Hello World",共输出 5 次: ```c #include <stdio.h> #include <signal.h> #include <time.h> timer_t timerid; void timer_handler(int signo) { static int count = 0; printf("Hello World\n"); count++; if (count >= 5) { timer_delete(timerid); } } int main() { struct sigevent sev; struct itimerspec its; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGUSR1; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCK_REALTIME, &sev, &timerid); its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; its.it_interval.tv_nsec = 0; timer_settime(timerid, 0, &its, NULL); signal(SIGUSR1, timer_handler); while (1) { // 等待信号 } return 0; } ``` 在上面的代码中,timer_create() 函数创建了一个 POSIX 定时器timer_settime() 函数设置了定时器的初始值和间隔,也就是每隔 1 秒触发一次定时器。在信号处理函数中,输出 "Hello World" 并计数,当计数达到 5 时,使用 timer_delete() 函数删除定时器。最后,程序进入一个死循环等待信号的到来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值