Linux使用一个定时器实现设置任意数量定时器功能【转】
转自:https://www.jb51.net/article/120748.htm
为什么需要这个功能,因为大多数计算机软件时钟系统通常只能有一个时钟触发一次中断。当运行多个任务时,我们会想要多个定时器 的时钟跟踪并发这样可以生成正确的时间重叠,操作系统这样做。 本例子是为了实现使用Linux下的一个定时器,实现任一数量的定时器功能。 首先我们需要一些数据类型用来描述时钟数据结构 #include <stdio.h>
#include<time.h>
#define TRUE 1
#define FALSE 0
#define MAX_TIMERS ... 最大时钟数量
typedef timerval TIME; 定义时间类型
#define VERY_LONG_TIME ... 最大时间长度
struct timer {
int inuse; 时钟是否可用
TIME time; 定时时间长度
char *event; 是否超时
} timers[MAX_TIMERS]; /* set of timers */ 每个定时器都以这个数据结构来描述,第一个成员用来描述时钟是否正在使用,第二个成员是这个定时器的定时时间,第三个成员是是一个指针,*event初始化应该为0,当他被置为1,我们知道这个定时器已经超时了,和他相关的任务可以执行。 接下来是定时器数组的初始化,这里将每个时钟inuse成员设置为FALSE,表示时钟不可用。 void
timers_init() {
struct timer *t;
for (t=timers;t<&timers[MAX_TIMERS];t++)
t->inuse = FALSE;
} 现在开始是结构实现部分 首先写到的timer_undeclare这个函数,这个函数与后面的timer_declare相对立。主要作用是清除一个定时器。 有很多方法可以用来保存定时器的定时记录。没有复杂时钟硬件的机器通常在每一个时钟周期处理一个中断处理程序。然后软件就在处理程序中获取系统时间,然后判断是否设置的定时器超时。 很多比较聪明的机器可以在硬件中设置定时时间,一旦时间超时,就触发一个硬件中断。这同样适用与软件中断。 他们通过一个 定义一个time_now来记录当前的系统时间,volatile告诉机器每次从寄存器取值,防止数据被系统优化。 volatile TIME time_now 接下来定义一系列数据来记录 timer_next 指接下来要我们想要计时的定时器。time_timer_set保存最后一次获取的系统时间。 struct timer *timer_next = NULL;/* timer we expect to run down next */
TIME time_timer_set; /* time when physical timer was set */
//取消一个定时器
void timer_undeclare(struct timer *t)
{
disable_interrupts();
if(!t->inuse)
{
enable_interrupts();
return ;
}
t->inuse=;
if(t==timer_next)
{
if(time(&time_now)<)
perror("time error");
timers_update(time_now-time_timer_set);
if(timer_next)
{
start_physical_timer(&timer_next->time);
time_timer_set=time_now;
}
}
enable_interrupts();
} timer_undeclare作用为取消一个定时器。首先让中断失效,这很重要,因为时钟数据结构数据是在各进程中共享的,是可以在其他中断中被修改的,为了防止不必要的错我,这个取消操作应该为一个原子操作。开始我们先检测是否这个时钟已经无效了。如果有效,则设置inuse使其失效。如果我们要取消的定时器正好是下一个期望等待的定时器。那我们要重新指定下一个期望等待的定时器。在此之前所有定时器都要更新一下前一个定时器已经走过的时间。 接下来我们看到timers_update(time_t ti)函数 //更新定时器表时间
void timers_update(time_t time)
{
static struct timer timer_last={
,
{},
NULL
};
timer_last.time.tv_sec=;
struct timer *t;
timer_next=&timer_last;
for(t=timers;t<&timers[MAX_TIMERS];t++)
{
if(t->inuse)
{
if(time<t->time.tv_sec){
t->time.tv_sec-=time;
if(t->time.tv_sec<\
timer_next->time.tv_sec)
timer_next=t;
}else
{
*(t->event)=;
t->inuse=;
}
}
}
if(!timer_next->inuse)timer_next=;
} 此函数作用是更新所有有效定时器的时间长,同时将timer_next指向当前延时时间最短的一个定时器。如没有定时器,则将timer_next设置为空。 timer_declare 加入一个定时器 struct timer * timer_declare(TIME *ti,char *event)
{
struct timer *t;
disable_interrupts();
for(t=timers;t<&timers[MAX_TIMERS];t++)
{
if(!t->inuse)break;
}
if(t==&timers[MAX_TIMERS])
{
enable_interrupts();
return ;
}
t->event=event;
t->time.tv_sec=ti->tv_sec;
t->time.tv_usec=ti->tv_usec;
if(!timer_next)
{
if(time(&time_now)<)
perror("time() error");
time_timer_set=time_now;
start_physical_timer(&((timer_next=t)->time));
}else if((ti->tv_sec+time_now)<(\
timer_next->time.tv_sec+time_timer_set))
{
if(time(&time_now)<)
perror("time error");
timers_update(time_now-time_timer_set);
time_timer_set=time_now;
start_physical_timer(&((timer_next=t)->time));
}else
{
}
t->inuse=;
enable_interrupts();
return t;
} 首先找到一个可用的定时器表项,设置相关参数。 接下来判断如果timer_next为空,那么说明定时器表项没有定时器需要定时,那我们直接将timer_next指向新加入定时器,开始计时。 如果新加入定时器需要延时时间比当前正在延时的定时器的剩余时间还要短,则更新定时器表,并计时当前加入的定时器。 在处理完当前定时器事件后,将新加入的定时器的inuse置1. 接下来是定时器中断处理函数 //定时器中断处理函数
void timer_interrupt_hander(int signo)
{
printf("interrupt_hander\n");
if(time(&time_now)<)
perror("time() error");
timers_update(time_now-time_timer_set);
if(timer_next)
{
time_timer_set=time_now;
start_physical_timer(&timer_next->time);
}
} 这里我们打印一串字符来证明定时器时间的触发,首先要做的先更新定时器表,然后将time_timer_set设置成当前系统时间,继续进行下一个定时器事件,直到所有定时器都处理完毕。 接下来几个是LINUX系统相关函数 //失效定时器中断
void disable_interrupts()
{sigset_t new_mask;
sigemptyset(&new_mask);
sigaddset(&new_mask,SIGALRM);
if(sigprocmask(SIG_BLOCK,&new_mask,NULL)<)
perror("SIG_BLOCK error");
}
//使能定时器中断
void enable_interrupts()
{
sigset_t new_mask;
sigemptyset(&new_mask);
sigaddset(&new_mask,SIGALRM);
if(sigprocmask(SIG_UNBLOCK,&new_mask,NULL)<)
perror("SIG_UNBLOCK error");
}
//开启一个定时器工作
void start_physical_timer(TIME* time)
{
if(signal(SIGALRM,timer_interrupt_hander)==SIG_ERR)
perror("signal error");
struct itimerval new_value;
sigset_t zero_mask;
sigemptyset(&zero_mask);
new_value.it_value.tv_sec=time->tv_sec;
new_value.it_value.tv_usec=time->tv_usec;
new_value.it_interval.tv_sec=;
new_value.it_interval.tv_usec=;
setitimer(ITIMER_REAL,&new_value,NULL);
sigsuspend(&zero_mask);
} 主函数测试部分 #include<stdio.h>
#include<signal.h>
#include"multtime.h"
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t pid;
TIME time1,time2,time3;
time1.tv_sec=;
time1.tv_usec=;
time2.tv_sec=;
time2.tv_usec=;
time3.tv_sec=;
time3.tv_usec=;
timer_init();
if((pid=fork())<)
{
perror("fork() error");
}
else if(pid==)
{
printf("child 1\n");
timer_undeclare(timer_declare(&time1,));
}
else
{
if((pid=fork())<)
{
perror("fork error");
}
else if(pid==)
{
printf("child 2\n");
timer_undeclare(timer_declare(&time3,));
}
else
{
printf("parent\n");
timer_undeclare(timer_declare(&time2,));
}
}
exit();
} 实验结果: parent
child
child
interrupt_hander
interrupt_hander
interrupt_hander 总结 以上所述是小编给大家介绍的Linux使用一个定时器实现设置任意数量定时器功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
Linux使用一个定时器实现设置任意数量定时器功能【转】的更多相关文章
- JS---动画函数封装:设置任意的一个元素,移动到指定的目标位置
动画函数封装:设置任意的一个元素,移动到指定的目标位置 <!DOCTYPE html> <html lang="en"> <head> < ...
- 请写一个php函数,可以接受任意数量的参数
请写一个php函数,可以接受任意数量的参数 这是一道面试题.怎么写这个函数呢? function fun(......) { } ----------------------------------- ...
- Python 构造一个可接受任意数量参数的函数
为了能让一个函数接受任意数量的位置参数,可以使用一个* 参数 在这个例子中,rest 是由所有其他位置参数组成的元组.然后我们在代码中把它当成了一个序列来进行后续的计算
- Linux是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的性能稳定的操作系统,可免费使用并自由传播。
Linux是一个基于POSIX和Unix的多用户.多任务.支持多线程和多CPU的性能稳定的操作系统,可免费使用并自由传播. Linux是众多操作系统之一 , 目前流行的服务器和 PC 端操作系统有 L ...
- Memcahce(MC)系列(两)Linux下一个Memcache安装
Linux下一个memcache安装 memcache是高性能.分布式的内存对象缓存系统,用于在动态应用中降低数据库负载.提升訪问速度.眼下用memcache解决互联网上的大用户读取是很流行的一种使用 ...
- linux—粘滞位的设置
粘滞位(Stickybit),或粘着位,是Unix文件系统权限的一个旗标.最常见的用法在目录上设置粘滞位,如此以来,只有目录内文件的所有者或者root才可以删除或移动该文件.如果不为目录设置粘滞位,任 ...
- Linux粘滞位的设置
粘滞位(Stickybit),或粘着位,是Unix文件系统权限的一个旗标.最常见的用法在目录上设置粘滞位,如此以来,只有目录内文件的所有者或者root才可以删除或移动该文件.如果不为目录设置粘滞位,任 ...
- 5-3 Linux内核计时、延时函数与内核定时器【转】
转自:http://www.xuebuyuan.com/510594.html 5-3 Linux内核计时.延时函数与内核定时器 计时 1. 内核时钟 1.1 内核通过定时器(timer)中断来跟 ...
- CSS之background-image:在一个元素中设置给定数量的背景图片
众所周知,可以通过设置background-repeat的值来改变背景图片的重复次数.但有一个问题,background-repeat的值不是让图片只有1个,就是让图片铺满.如果只想设置给定数量的图片 ...
随机推荐
- 2017-2018 第一学期201623班《程序设计与数据结构》-第5&6周作业问题总结
一.作业内容 第5周作业 http://www.cnblogs.com/rocedu/p/7484252.html#WEEK05 第6周作业 http://www.cnblogs.com/rocedu ...
- Day Six
站立式会议 站立式会议内容总结 442 今天:实现计划界面的逻辑 遇到的问题:模态框问题 明天:解决上面问题,开始使用动态数据 331 今天:点击添加找到文件 遇到问题:找到文件在app的引入实现 明 ...
- vs安装体验
鉴于vs都是英文,所以安装的时间实在是太长了,经过4个小时终于装完了. 首先要下载和安装Unit Test Generator.步骤为:tools->Extensions and Updates ...
- jenkins 添加 k8s 云
同事的jenkins 链接自己的 k8s 总是出问题 给出了资料和服务器 进行处理. 同时给出的参考资料:https://blog.csdn.net/diantun00/article/details ...
- .NET获取文件的MIME类型(Content Type)
第一种:这种获取MIME类型(Content Type)的方法需要在.NET 4.5之后才能够支持,但是非常简单. 优点:方便快捷 缺点:只能在.NET 4.5之后使用 public FileResu ...
- Before NOIP2017
明天就比赛了呢! 说起来,这是我第二次,可能也是最后一次正式参加提高组的比赛了. 虽然是从初中就有参加信息学的学习,但是认真学习信息竞赛还是去年七月开始的.NOIP2016 中,我凭着两天的简单题和一 ...
- 【刷题】BZOJ 4543 [POI2014]Hotel加强版
Description 同OJ3522 数据范围:n<=100000 Solution dp的设计见[刷题]BZOJ 3522 [Poi2014]Hotel 然后发现dp的第二维与深度有关,于是 ...
- 【POJ2728】Desert King 最优比率生成树
题目大意:给定一个 N 个点的无向完全图,边有两个不同性质的边权,求该无向图的一棵最优比例生成树,使得性质为 A 的边权和比性质为 B 的边权和最小. 题解:要求的答案可以看成是 0-1 分数规划问题 ...
- PHP内核-代码的执行(二)
学习来源:http://www.php-internals.com/book/?p=chapt02/02-00-overview 最开始学习PHP的时候感觉上手真的好容易,噼里啪啦一个回车 “Hell ...
- java基础基础总结----- String