在服务端程序设计中,与时间有关的常见任务有:

  1. 获取当前时间,计算时间间隔;
  2. 定时操作,比如在预定的时间执行一项任务,或者在一段延时之后执行一项任务。

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平台上它是用户态实现的,没有系统调用和上下文切换的开销。

定时函数中:

  1. sleep / alarm / usleep 在实现时有可能用了信号 SIGALRM,在多线程程序中处理信号是个相当麻烦的事情,应当尽量避免。(近期我会写一篇博客仔细讲讲“多线程、RAII、fork() 与信号”)
  2. nanosleep 和 clock_nanosleep 是线程安全的,但是在非阻塞网络编程中,绝对不能用让线程挂起的方式来等待一段时间,程序会失去响应。正确的做法是注册一个时间回调函数。
  3. getitimer 和 timer_create 也是用信号来 deliver 超时,在多线程程序中也会有麻烦。timer_create 可以指定信号的接收方是进程还是线程,算是一个进步,不过在信号处理函数(signal handler)能做的事情实在很受限。
  4. timerfd_create 把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,这样就能很方便地融入到 select/poll 框架中,用统一的方式来处理 IO 事件和超时事件。l
  5. 利用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的定时器的更多相关文章

  1. 芯灵思Sinlinx A64开发板Linux内核定时器编程

    开发平台 芯灵思Sinlinx A64 内存: 1GB 存储: 4GB 开发板详细参数 https://m.tb.cn/h.3wMaSKm 开发板交流群 641395230 Linux 内核定时器是内 ...

  2. 全志A33开发板Linux内核定时器编程

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...

  3. 芯灵思SinlinxA33开发板Linux内核定时器编程

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 Linux 内核定时器是内核 ...

  4. 模仿linux内核定时器代码,用python语言实现定时器

    大学无聊的时候看过linux内核的定时器,如今已经想不起来了,也不知道当时有没有看懂,如今想要模仿linux内核的定时器.用python写一个定时器,已经想不起来它的设计原理了.找了一篇blog,li ...

  5. Linux内核定时器

    Linux使用struct    timer_list来描述一个定时器. 重要成员: expires:定时时长 *function:超时执行函数名使用流程: 1.定义定时器变量 /*定义定时器变量结构 ...

  6. Linux内核——定时器和时间管理

    定时器和时间管理 系统定时器是一种可编程硬件芯片.它能以固定频率产生中断.该中断就是所谓的定时器中断.它所相应的中断处理程序负责更新系统时间,还负责执行须要周期性执行的任务. 系统定时器和时钟中断处理 ...

  7. Linux下定时器

    http://unix8.net/linux%E4%B8%8B%E5%AE%9A%E6%97%B6%E5%99%A8.html 一. 基础知识 1.时间类型.Linux下常用的时间类型有4个:time ...

  8. Linux之定时器与时间管理 【转】

    转自:http://blog.chinaunix.net/uid-23228758-id-154820.html 定时器与时间管理: 次,为一秒.一般的情况下编程者不要改变这个值,因为内核编很多代码都 ...

  9. Linux使用定时器timerfd 和 eventfd接口实现进程线程通信

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  10. Linux Timer定时器【转】

    转自:https://www.jianshu.com/p/66b3c75cae81 timerfd为Linux为用户程序提供的定时器接口,该接口基于文件描述符,通过文件描述符的可读事件进行超时通知,且 ...

随机推荐

  1. [BZOJ2669][CQOI2012]局部最小值(容斥+状压DP)

    发现最多有8个限制位置,可以以此为基础DP和容斥. $f_{i,j}=f_{i-1,j}\times (cnt_j-i+1)+\sum_{k\subset j} f_{i-1,k}$ $cnt_j$表 ...

  2. AtCoder - 4162 Independence

    Problem Statement In the State of Takahashi in AtCoderian Federation, there are N cities, numbered 1 ...

  3. [CODECHEF]TREECNT2

    题意:一棵带边权的树,边权可单边修改,问初始时和每次修改后有多少条路径$\gcd=1$ 首先考虑用反演求答案,设$f(n)$为路径$\gcd=n$的路径条数,$g(n)$为路径$\gcd$是$n$倍数 ...

  4. Mac下的MySQL修改默认连接字符集

    进入命令行执行以下命令: sudo vim /etc/my.cnf [client] default-character-set=utf8 [mysqld] character-set-server= ...

  5. HMAC的JAVA实现和应用

    1.简介: HMACSHA1 是从SHA1 哈希函数构造的一种键控哈希算法,被用作 HMAC(基于哈希的消息验证代码). 此 HMAC 进程将密钥与消息数据混合,使用哈希函数对混合结果进行哈希计算,将 ...

  6. 【maven】ecplise新建maven项目 报错Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin

    在ecplise上新建maven项目 报错: Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resourc ...

  7. C语言基本数据类型简介

    1.概述 C 语言包含的数据类型如下图所示: 2.各种数据类型介绍 2.1整型 整形包括短整型.整形和长整形. 2.1.1短整形 short a=1; 2.1.2整形 一般占4个字节(32位),最高位 ...

  8. Unity3D手机游戏开发

    <Unity3D手机游戏开发> 基本信息 作者: 金玺曾 出版社:清华大学出版社 ISBN:9787302325550 上架时间:2013-8-7 出版日期:2013 年8月 开本:16开 ...

  9. jquery接收后台数组或集合回显复选框

    公司使用的框架比较旧,没有使用el等表达式.如果后台传递的是数组,需要把数组转为以逗号分隔的字符串. <% String context = request.getContextPath(); ...

  10. js中setinterval 的相关使用

    1.setinterval 方法 setinterval()是定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式. 2.创建一个setinterval 方法 setInterval(s ...