linux下定时器介绍1
POSIX Timer
间隔定时器 setitimer 有一些重要的缺点,POSIX Timer 对 setitimer 进行了增强,克服了 setitimer 的诸多问题:
首先,一个进程同一时刻只能有一个 timer。假如应用需要同时维护多个 Interval 不同的计时器,必须自己写代码来维护。这非常不方便。使用 POSIX Timer,一个进程可以创建任意多个 Timer。
setitmer 计时器时间到达时,只能使用信号方式通知使用 timer 的进程,而 POSIX timer 可以有多种通知方式,比如信号,或者启动线程。
使用 setitimer 时,通知信号的类别不能改变:SIGALARM,SIGPROF 等,而这些都是传统信号,而不是实时信号,因此有 timer overrun 的问题;而 POSIX Timer 则可以使用实时信号。
setimer 的精度是 ms,POSIX Timer 是针对有实时要求的应用所设计的,接口支持 ns 级别的时钟精度。
表 2. POSIX Timer 函数
| 函数名 | 功能描述 |
|---|---|
timer_create |
创建一个新的 Timer;并且指定定时器到时通知机制 |
timer_delete |
删除一个 Timer |
timer_gettime |
Get the time remaining on a POSIX.1b interval timer |
timer_settime |
开始或者停止某个定时器。 |
timer_getoverrun |
获取丢失的定时通知个数。 |
使用 Posix Timer 的基本流程很简单,首先创建一个 Timer。创建的时候可以指定该 Timer 的一些特性,比如 clock ID。
clock ID 即 Timer 的种类,可以为下表中的任意一种:
表 3. POSIX Timer clock ID
| Clock ID | 描述 |
|---|---|
| CLOCK_REALTIME | Settable system-wide real-time clock; |
| CLOCK_MONOTONIC | Nonsettable monotonic clock |
| CLOCK_PROCESS_CPUTIME_ID | Per-process CPU-time clock |
| CLOCK_THREAD_CPUTIME_ID | Per-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 用来设置定时器到时时的通知方式。该数据结构如下:
清单 10,结构 sigevent
struct sigevent {
|
其中 sigev_notify 表示通知方式,有如下几种:
表 3. 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 的时候使用到,应用程序很少会需要用到这种模式。
启动定时器
创建 Timer 之后,便可以调用 timer_settime() 函数指定定时器的时间间隔,并启动该定时器了。
int timer_settime(timer_t timerid, int flags, |
第一次看到 timer_settime 的参数列表或许会令人觉得费解。先来看看 new_value 和 old_value,它们都是 struct itimerspec 数据结构。
struct itimerspec |
启动和停止 Timer 都可以通过设置 new_value 来实现:
new_value->it_interval 为定时器的周期值,比如 1 秒,表示定时器每隔 1 秒到期;
new_value->it_value 如果大于 0,表示启动定时器,Timer 将在 it_value 这么长的时间过去后到期,此后每隔 it_interval 便到期一次。如果 it_value 为 0,表示停止该 Timer。
有些时候,应用程序会先启动用一个时间间隔启动定时器,随后又修改该定时器的时间间隔,这都可以通过修改 new_value 来实现;假如应用程序在修改了时间间隔之后希望了解之前的时间间隔设置,则传入一个非 NULL 的 old_value 指针,这样在 timer_settime() 调用返回时,old_value 就保存了上一次 Timer 的时间间隔设置。多数情况下我们并不需要这样,便可以简单地将 old_value 设置为 NULL,忽略它。
下面给出一个使用 posix timer 的例子程序。最传统的例子就是创建通知方式为 SIGEV_SIGNAL 的 Timer。这样当定时器到期时,将产生信号通知,主程序需要定义自己的信号处理函数,来处理信号到期事件。这种例子比比皆是,我打算在这里写一个采用通知方式为 SIGEV_THREAD 的例子。该例子程序从 main 函数开始主线程,在开始的时候打印出主线程的进程 ID 和线程 ID。
清单 11,打印 TID
pid_t tid = (pid_t) syscall (SYS_gettid); |
获得 ThreadID 的系统调用尚未被 GLibC 标准化,因此这里直接调用 syscall。
然后,主线程初始化创建 Timer 所需要的数据结构:
清单 12,设置通知方式
se.sigev_notify = SIGEV_THREAD; |
这里将通知方式设为 SIGEV_THREAD,timer_thread 为线程入口函数。
然后主线程设置定时器间隔,并启动 Timer:
清单 13,启动 Timer
ts.it_value.tv_sec = 5; |
此后主线程进入一个循环,在循环中等待线程条件变量:
清单 14,主程序中的循环
while (counter < 5) {
|
条件变量 cond 将在 timer_thread() 处理函数中触发,这样每 5 秒钟,定时器将调用 timer_thread() 处理函数,并唤醒主线程等待的条件变量一次。5 次之后测试程序退出。
现在我们看看 timer_thread() 函数:
清单 15,timer_thread 函数
void timer_thread (void *arg) |
在整个程序中我们都没有使用信号,定时器到期时,将启动新的线程运行 timer_thread。因此在该函数中,我们还打印了当前的线程号以便可以看出它们确实在不同线程中运行。
这里是运行该程序的一个输出:
-bash-3.2$ gcc threadtimer.c -lrt -lpthread -o test |
可以看到每次 Timer 都运行在不同的线程中。
linux下定时器介绍1的更多相关文章
- linux下定时器介绍2--timer_create等函数集的使用示例
程序1:采用新线程派驻的通知方式 程序2:通知方式为信号的处理方式 #include <stdio.h>#include <time.h>#include <stdlib ...
- .Neter玩转Linux系列之四:Linux下shell介绍以及TCP、IP基础
基础篇 .Neter玩转Linux系列之一:初识Linux .Neter玩转Linux系列之二:Linux下的文件目录及文件目录的权限 .Neter玩转Linux系列之三:Linux下的分区讲解 .N ...
- Linux下tmpfs介绍及使用
tmpfs介绍 tmpfs是一种虚拟内存文件系统,而不是块设备.是基于内存的文件系统,创建时不需要使用mkfs等初始化它最大的特点就是它的存储空间在VM(virtual memory),VM是由lin ...
- Linux下定时器
http://unix8.net/linux%E4%B8%8B%E5%AE%9A%E6%97%B6%E5%99%A8.html 一. 基础知识 1.时间类型.Linux下常用的时间类型有4个:time ...
- linux下定时器的实现
简介: linux下经常有这样的需求,需要定时轮询执行某种任务,当然,用shell脚本的话,crontab和at就可以满足要求.如果从C语言的角度来看,实现定时器也是一个比较简单的任务,因为具有普遍性 ...
- 06 Linux下Shell介绍
一.概述 每个人在成功登陆Linux后,系统会出现不同的提示符号,例如$,~,#等,然后你就可以开始输入需要的命令.若命令正确,系统就会依据命令的要求来执行,直到注销系统为止,在登陆到注销期间,输入的 ...
- LINUX下FD_SET介绍
刚刚了解了linux下select系统调用,函数原型是 #include <sys/select.h> #include <sys/time.h> int select(int ...
- 转://Linux下tmpfs介绍及使用
tmpfs介绍 tmpfs是一种虚拟内存文件系统,而不是块设备.是基于内存的文件系统,创建时不需要使用mkfs等初始化它最大的特点就是它的存储空间在VM(virtual memory),VM是由lin ...
- Linux下iptables介绍
ptables简介 iptables是基于内核的防火墙,功能非常强大,iptables内置了filter,nat和mangle三张表. filter负责过滤数据包,包括的规则链有,input,outp ...
随机推荐
- BZOJ5104 Fib数列(二次剩余+BSGS)
5在1e9+9下有二次剩余,那么fib的通项公式就有用了. 已知Fn,求n.注意到[(1+√5)/2]·[(1-√5)/2]=-1,于是换元,设t=[(1+√5)/2]n,原式变为√5·Fn=t-(- ...
- BZOJ3512 DZY Loves Math IV(杜教筛+线性筛)
注意到n很小,考虑枚举i.现在要求的是f(n,m)=Σφ(in) (i=1~m).显然当n没有平方因子时,φ(in)=φ(i)·φ(n/gcd(i,n))·gcd(i,n).利用φ*1=id又可得φ( ...
- P3216 [HNOI2011]数学作业
题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M ,要求计算Concatenate (1 .. N) Mod M 的值,其中 Concatenat ...
- python的==和is区别
Python中: is判断两个标识符是否引自同一个对象 ==判断两个标识符的值是否相等 区别于java: ==判断两个标识符是否引自同一个对象 .equals()判断是否相等 #如果是String ...
- ZJOI 2018 一试记
ZJOI一试几天,天微冷,雨.倒是考试当天近午时分出了太阳. 开题前的一刻,心情反而平静了,窗外泛着淡金色的日光照进来,仿佛今天的我并不是所谓来冲击省队,而只是来经历一场洗礼. 开题了,虽然有一点小插 ...
- 解题:CF983B pyramid
题面 题目都告诉我们是“金字塔”了,不妨分析分析$f$的性质 $f(a_1,a_2)=f(a_1$ $xor$ $a_2)=a1$ $xor$ $a_2$ $f(a_1,a_2,a_3)=f(a_1$ ...
- bzoj 2300 : [HAOI2011]防线修建
set动态维护凸包 #include<iostream> #include<cstdio> #include<cstring> #include<algori ...
- 【2018北京集训(六)】Lcm
Portal --> 出错啦qwq(好吧其实是没有) Description 给定两个正整数\(n,k\),选择一些互不相同的正整数,满足这些数的最小公倍数恰好为\(n\),并且这些数的和为\( ...
- Harris角点及Shi-Tomasi角点检测(转)
一.角点定义 有定义角点的几段话: 1.角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测.图像匹配.视频跟踪.三维建模和目标识别等领域中.也 ...
- [python]python安装包错误
“UnicodeDecodeError: ‘ascii’ codec can’t decode : ordinal not )” 在windows XP上 解决方法: Solution: ====== ...