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个,就是让图片铺满.如果只想设置给定数量的图片 ...
随机推荐
- Day Four
站立式会议 站立式会议内容总结 442 今天:整合主页两个部分的逻辑代码,主页及其跳转基本完成 遇到的问题:无 明天:阅读图书界面逻辑部分完成 331 今天:学习java反射添加类数据到数据库 遇到问 ...
- beta5
吴晓晖(组长) 过去两天完成了哪些任务 完善推荐算法 展示GitHub当日代码/文档签入记录 接下来的计划 推荐算法 还剩下哪些任务 组员:刘帅珍 过去两天完成了哪些任务: 修改原型,整理背景 明日计 ...
- OpenFlow PacketOut消息机制
OpenFlow PacketOut消息机制 前言 由于最近实验的进行,遇到一个比较棘手的问题,就是利用控制器主动发送packet消息的问题,期间遇到一些问题,后来在RYU群中得到群友左木的帮助成功解 ...
- [转帖] Linux 下面 Find的使用...--- 自己不会用 find
13个实用的Linux find命令示例 原始博客地址: https://www.cnblogs.com/chenshoubiao/p/4838089.html 之前只会用locate 基础 ...
- QT试验(1)
今天,用Qt Creator写第一个简单的小程序“HelloQt”,运行时报错:error: cannot open C:\Users\敏\AppData\Local\Temp\main.obj.51 ...
- Java内置锁synchronized的实现原理
简述Java中每个对象都可以用来实现一个同步的锁,这些锁被称为内置锁(Intrinsic Lock)或监视器锁(Monitor Lock). 具体表现形式如下: 1.普通同步方法,锁的是当前实例对象 ...
- python updata与深拷贝
当使用updata更新字典时候 被动更新和主动更新的效果是一样的 意思是说 里面会添加值 而不是保持不变 当将一个字典每次新增到列表时候 要用深拷贝 因为直接append的话 会修改将最新的变量的值同 ...
- 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...
- 【数论Day1】 最大公约数(gcd)题目
20170529-3数论_gcd 题解: http://www.cnblogs.com/ljc20020730/p/6919116.html 日期 序号 题目名称 输入文件名 输出文件名 时限 内存 ...
- 【转】SPI总线协议
SPI总线协议 By Xiaomin | April 17, 2016| 技术 概述 SPI(Serial Peripheral Interface)总线是主要应用于嵌入式系统内部通信的串行同步传输总 ...