Linux的定时器
在服务端程序设计中,与时间有关的常见任务有:
- 获取当前时间,计算时间间隔;
- 定时操作,比如在预定的时间执行一项任务,或者在一段延时之后执行一项任务。
Linux 时间函数
Linux 的计时函数,用于获得当前时间:
- time(2) / time_t (秒)
- ftime(3) / struct timeb (毫秒)
- gettimeofday(2) / struct timeval (微秒)
- clock_gettime(2) / struct timespec (纳秒)
- gmtime / localtime / timegm / mktime / strftime / struct tm (这些与当前时间无关)
定时函数,用于让程序等待一段时间或安排计划任务:
- sleep
- alarm
- getitimer / setitimer
- timer_create / timer_settime / timer_gettime / timer_delete
- timerfd_create / timerfd_gettime / timerfd_settime
- 条件变量pthread_cond_timedwait实现
- IO多路复用select, epoll实现
一般情况下
获取当前时间常用
gettimerofday,因为它的精度是1us,并且在x86平台上它是用户态实现的,没有系统调用和上下文切换的开销。
定时函数中:
- sleep / alarm / usleep 在实现时有可能用了信号 SIGALRM,在多线程程序中处理信号是个相当麻烦的事情,应当尽量避免。(近期我会写一篇博客仔细讲讲“多线程、RAII、fork() 与信号”)
- nanosleep 和 clock_nanosleep 是线程安全的,但是在非阻塞网络编程中,绝对不能用让线程挂起的方式来等待一段时间,程序会失去响应。正确的做法是注册一个时间回调函数。
- getitimer 和 timer_create 也是用信号来 deliver 超时,在多线程程序中也会有麻烦。timer_create 可以指定信号的接收方是进程还是线程,算是一个进步,不过在信号处理函数(signal handler)能做的事情实在很受限。
- timerfd_create 把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,这样就能很方便地融入到 select/poll 框架中,用统一的方式来处理 IO 事件和超时事件。l
- 利用select, epoll的timeout实现定时功能,它们的缺点是定时精度只有毫秒,远低于 timerfd_settime 的定时精度。
实现
下面是用timer_create实现的一个定时器:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h> void sig_handler(int signo)
{
switch(signo) {
case SIGUSR1:
printf("receive sigusr1! \n");
break;
case SIGALRM:
printf("receive sigarlm!\n");
break;
}
} int main()
{
/**
struct sigaction
{
void (*sa_handler)(int);信号响应函数地址
void (*sa_sigaction)(int, siginfo_t *, void *); 但sa_flags为SA——SIGINFO时才使用
sigset_t sa_mask; 说明一个信号集在调用捕捉函数之前,会加入进程的屏蔽中,当捕捉函数返回时,还原
int sa_flags;
void (*sa_restorer)(void);未用
};
*/
timer_t timer1, timer2;
struct sigevent evp1, evp2;
struct sigaction act; //for timer1
memset(&act, 0, sizeof(act));
act.sa_handler = sig_handler;
act.sa_flags = 0; sigemptyset(&act.sa_mask); if (sigaction(SIGUSR1, &act, NULL) == -1) {
perror("fail to sigaction");
exit(-1);
} //for timer2
memset(&act, 0, sizeof(act));
act.sa_handler = sig_handler;
act.sa_flags = 0; sigemptyset(&act.sa_mask); if (sigaction(SIGALRM, &act, NULL) == -1) {
perror("fail to sigaction");
exit(-1);
}
//for timer1
memset(&evp1, 0, sizeof(struct sigevent));
evp1.sigev_signo = SIGUSR1;
evp1.sigev_notify = SIGEV_SIGNAL;
if (timer_create(CLOCK_REALTIME, &evp1, &timer1) == -1) {
perror("fail to timer_create");
exit(-1);
} struct itimerspec it;
it.it_interval.tv_sec = 2;
it.it_interval.tv_nsec = 0;
it.it_value.tv_sec = 1;
it.it_value.tv_nsec = 0;
if (timer_settime(timer1, 0, &it, 0) == -1) {
perror("fail to timer_settime");
exit(-1);
} //for timer2
memset(&evp2, 0, sizeof(struct sigevent));
evp2.sigev_signo = SIGALRM;
evp2.sigev_notify = SIGEV_SIGNAL;
if (timer_create(CLOCK_REALTIME, &evp2, &timer2) == -1) {
perror("fail to timer_create");
exit(-1);
}
it.it_interval.tv_sec = 4;
it.it_interval.tv_nsec = 0;
it.it_value.tv_sec = 2;
it.it_value.tv_nsec = 0;
if (timer_settime(timer2, 0, &it, 0) == -1) {
perror("fail to timer_settime");
exit(-1);
} for(;;); return 0;
}
以及一个用setitimer实现的定时器
setitimer中的第一个参数有三类:
这里说得很清楚。
ITIMER_REAL decrements in real time, and delivers SIGALRM upon expiration. ITIMER_VIRTUAL decrements only when the process is executing, and delivers SIGVTALRM upon expiration. ITIMER_PROF decrements both when the process executes and when the system is executing on behalf of the process. Coupled with ITIMER_VIRTUAL, this timer is usually used to profile the time spent by the application in user and kernel space. SIGPROF is delivered upon expiration.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h> void timer_handler (int signum)
{
switch(signum) {
case SIGALRM:
printf("sigarlm !\n");
break;
case SIGVTALRM:
printf("sigvtalrm !\n");
break;
}
} int main ()
{
struct sigaction sa;
struct itimerval timer;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
sigaction (SIGVTALRM, &sa, NULL); sa.sa_handler = &timer_handler;
sigaction(SIGALRM, &sa, NULL); timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000; setitimer (ITIMER_REAL, &timer, NULL); timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &timer, NULL); while (1);
}
参考:http://www.cnblogs.com/Solstice/archive/2011/02/06/1949555.html
Linux的定时器的更多相关文章
- 芯灵思Sinlinx A64开发板Linux内核定时器编程
开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 Linux 内核定时器是内 ...
- 全志A33开发板Linux内核定时器编程
开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...
- 芯灵思SinlinxA33开发板Linux内核定时器编程
开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...
- 模仿linux内核定时器代码,用python语言实现定时器
大学无聊的时候看过linux内核的定时器,如今已经想不起来了,也不知道当时有没有看懂,如今想要模仿linux内核的定时器.用python写一个定时器,已经想不起来它的设计原理了.找了一篇blog,li ...
- Linux内核定时器
Linux使用struct timer_list来描述一个定时器. 重要成员: expires:定时时长 *function:超时执行函数名使用流程: 1.定义定时器变量 /*定义定时器变量结构 ...
- Linux内核——定时器和时间管理
定时器和时间管理 系统定时器是一种可编程硬件芯片.它能以固定频率产生中断.该中断就是所谓的定时器中断.它所相应的中断处理程序负责更新系统时间,还负责执行须要周期性执行的任务. 系统定时器和时钟中断处理 ...
- Linux下定时器
http://unix8.net/linux%E4%B8%8B%E5%AE%9A%E6%97%B6%E5%99%A8.html 一. 基础知识 1.时间类型.Linux下常用的时间类型有4个:time ...
- Linux之定时器与时间管理 【转】
转自:http://blog.chinaunix.net/uid-23228758-id-154820.html 定时器与时间管理: 次,为一秒.一般的情况下编程者不要改变这个值,因为内核编很多代码都 ...
- Linux使用定时器timerfd 和 eventfd接口实现进程线程通信
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- Linux Timer定时器【转】
转自:https://www.jianshu.com/p/66b3c75cae81 timerfd为Linux为用户程序提供的定时器接口,该接口基于文件描述符,通过文件描述符的可读事件进行超时通知,且 ...
随机推荐
- 2017 Multi-University Training 1 解题报告
Add More Zero Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- HDU 6044 Limited Permutation(搜索+读入优化)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6044 [题目大意] 给出两个序列li,ri,现在要求构造排列p,使得对于区间[li,ri]来说, ...
- [洛谷P3809]【模板】后缀排序
[洛谷P3809][模板]后缀排序 题目大意: 对于给定的长度为\(n(n\le10^6)\)的字符串求后缀数组\(sa[i]\). 思路: 倍增+快排构造后缀数组.代码参考<挑战程序设计竞赛& ...
- Activit(活动)实践--知晓当前活动
实际上,我们可能用的不是自己写的项目,而是从别人那里接手过来的代码,因为你刚进公司就有一个新项目开始的概率十分低.阅读别人代码时会有一个很头疼的问题,就是当你需要在某个界面上修改一些非常简单的东西时, ...
- 关于abstract class 和 interface
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系.但是,一个类却可以实现多个interface. 2.在abstract class 中可以有自己 ...
- Luci实现框架
转自:http://www.cnblogs.com/zmkeil/archive/2013/05/14/3078774.html 1.总述 上一篇总结了uhttpd的工作方式,openwrt中利用它作 ...
- 发一个比trace功能更强大debug工具,MonterDebugger
经常看到兄弟说trace不出东西啊,这样给你调试会带来很多不便:加入说我们需要将运行时的debug信息和之前某个版本的进行比对:又加入说我们需要在运行时通过debug动态调整显示对象的属性:查看当前整 ...
- 工作中常用Lixu命令学习笔记
对于Linux,我是菜鸟,也是在工作中了才开始慢慢接触,用Linux的人都我都会觉得屌屌的,现在把工作中常用的一些Linux命令记录一下,供以后学习和参考. cd 这可能是我觉得Linux最简单的一个 ...
- POI创建Excel使用的常见的属性
public static void main(String[] args) { //创建新的Excel 工作簿 HSSFWorkbook workbook =new HSSFWorkbook(); ...
- Objective-C:KVC机制
KVC:key value coding 键值对的编码 功能:用来给对象属性设置值或者取出对象属性的值.虽然getter和setter方法也是该功能,但是如果类中没有设置属性特性或者重写这两个方 ...