Linux多定时器实现
一、setitimer函数
1. 头文件
#include <sys/time.h>
2. 函数原型
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
- which参数说明:
ITIMER_REAL:给一个指定的时间间隔,按照实际的时间来减少这个计数,当时间间隔为0的时候发出SIGALRM信号;
ITIMER_VIRTUAL:给定一个时间间隔,当进程执行的时候才减少计数,时间间隔为0的时候发出SIGVTALRM信号;
ITIMER_PROF:给定一个时间间隔,当进程执行或者是系统为进程调度的时候,减少计数,时间到了,发出SIGPROF信号。
- new_value參数
用来对计时器进行设置;
- old_value參数
通经常使用不上。设置为NULL,它是用来存储上一次setitimer调用时设置的new_value值。
3. 结构体
struct itimerval {
struct timeval it_interval; /* timer interval */
struct timeval it_value; /* current value */
};
struct timeval {
__kernel_time_t tv_sec; /* seconds */
__kernel_suseconds_t tv_usec; /* microseconds */
};
itimeval又是由两个timeval结构体组成,timeval包括tv_sec和tv_usec两部分。当中tv_se为秒。tv_usec为微秒(即1/1000000秒)。当中的new_value參数用来对计时器进行设置,it_interval为计时间隔,it_value为延时时长,是在setitimer方法调用成功后,延时it_value便触发一次SIGALRM信号,以后每隔it_interval触发一次SIGALRM信号。
settimer工作机制是,先对it_value倒计时,当it_value为零时触发信号。然后重置为it_interval。继续对it_value倒计时。一直这样循环下去。
基于此机制。setitimer既能够用来延时运行,也可定时运行。
假如it_value为0是不会触发信号的,所以要能触发信号,it_value得大于0;假设it_interval为零,仅仅会延时。不会定时(也就是说仅仅会触发一次信号)。
二、多定时器实现一
这里采用 定时器+list方式实现多定时器,如下
头文件:tw_timer.h
#ifndef _TW_TIMER_PUBLIC_H_
#define _TW_TIMER_PUBLIC_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include<pthread.h>
typedef signed char SINT8;
typedef unsigned char UINT8;
typedef short SINT16;
typedef unsigned short UINT16;
typedef long SINT32;
typedef UINT8 BITS;
typedef unsigned long UINT32;
typedef unsigned long long UINT64;
typedef long long SINT64;
typedef float FLOAT;
typedef double DOUBLE;
typedef int BOOL;
typedef void VOID;
typedef char CHAR;
#define HWND unsigned int
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef int (* ONTIMERPROC)(HWND, VOID *);
typedef struct tMultiTimer
{
UINT8 nTimerID; //定时器ID
UINT32 nHWND; //当前活动ID
UINT32 nInterval; //定时时长
UINT32 gCount; //计数
BOOL bIsSingleUse; //是否循环
ONTIMERPROC pTimeoutCallbackfunction; //回调函数
void* pTimeoutCallbackParameter; //回调函数参数
struct tMultiTimer* pNextTimer; //链表后驱指针
}tMultiTimer;
tMultiTimer* g_pTimeoutCheckListHead = NULL; //管理多定时器的全局链表
#define PUBLIC_TIMER_MAX 18/*同时运行的最大Timer数,超过不予创建*/
#define TIMER_FAILURE 0xffffffff
#define TIMERID_BASE 0x0AB0
/**************************************************************************
* 函数名称:Tw_createTimer
* 功能描述:创建一个定时器,定时器到执行用户指定回调
**************************************************************************/
SINT32 Tw_createTimer(HWND hWnd, SINT32 intval, ONTIMERPROC onTimerProc, VOID* data, BOOL bLoop);
/**************************************************************************
* 函数名称:Tw_destroyTimer
* 功能描述:销毁指定定时器
**************************************************************************/
SINT8 Tw_destroyTimer(HWND hWnd, SINT32 timerID);
/**************************************************************************
* Tw_destroyAllTimer
* 功能描述:销毁所有用户自定添加的定时任务
* 参数说明:无
* 返 回 值: 无
* 其它说明:进程结束一定要删除所有定时器
**************************************************************************/
VOID Tw_destroyAllTimer(void);
/**************************************************************************
* Tw_Init_time_back
* 功能描述:初始化定时器回调函数
**************************************************************************/
VOID Tw_Init_time_back(int arg);
/**************************************************************************
* Tw_InitTimer
* 功能描述:初始化定时器
**************************************************************************/
SINT32 Tw_InitTimer(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _CTRLEX_TIMER_PUBLIC_H_ */
源文件:tw_timer.c
#include "tw_timer.h"
#define TW_INIT_TIME 1000
static SINT32 g_timer_count = 0;
VOID Tw_Init_time_back(int arg)
{
tMultiTimer *p1=g_pTimeoutCheckListHead;
if(g_pTimeoutCheckListHead == NULL)
{
return ;//无定时任务
}
else
{
while( p1 !=NULL) //
{
p1->gCount ++;
if(p1->gCount == p1->nInterval)
{
p1->gCount = 0;
p1->pTimeoutCallbackfunction(p1->nHWND,p1->pTimeoutCallbackParameter);
if(p1->bIsSingleUse == 1)//单次有效
Tw_destroyTimer(p1->nHWND,p1->nTimerID);
}
p1=p1->pNextTimer;
}
}
//printf(" Tw_createTimer start\n");
return ;
}
SINT32 Tw_InitTimer(void)
{
SINT32 ret = 0;
signal(SIGALRM,Tw_Init_time_back);
struct itimerval tick;
memset(&tick, 0, sizeof(tick));
tick.it_value.tv_sec = 0;
tick.it_value.tv_usec = TW_INIT_TIME; //after TIMER_LEN time,start Timer
tick.it_interval.tv_sec = 0;
tick.it_interval.tv_usec =TW_INIT_TIME; //every TIMER_LEN Time,run Timer function
ret = setitimer((int) ITIMER_REAL, &tick, NULL);
//printf(" Tw_createTimer start\n");
return ret;
}
SINT32 Tw_createTimer(HWND hWnd, SINT32 intval, ONTIMERPROC onTimerProc, VOID* data, BOOL bLoop)
{
tMultiTimer *p2=(tMultiTimer *)malloc(sizeof(tMultiTimer));
bzero(p2,sizeof(tMultiTimer));
tMultiTimer *p1=g_pTimeoutCheckListHead;
if(g_pTimeoutCheckListHead == NULL)
{
g_pTimeoutCheckListHead = p2;
p2->pNextTimer=NULL;
p1=p2;
}
else
{
while(p1->pNextTimer !=NULL)
{
p1=p1->pNextTimer;
}
p1->pNextTimer=p2;
p1=p2;
p2->pNextTimer=NULL;
}
g_timer_count ++;
p2->nTimerID = g_timer_count;
p2->nHWND = hWnd;
p2->nInterval = intval;
p2->bIsSingleUse = bLoop;
p2->pTimeoutCallbackfunction = onTimerProc;
p2->pTimeoutCallbackParameter = NULL;
printf(" Tw_createTimer start\n");
return g_timer_count;
}
SINT8 Tw_destroyTimer(HWND hWnd, SINT32 timerID)
{
tMultiTimer *p3=g_pTimeoutCheckListHead;
tMultiTimer *p2=g_pTimeoutCheckListHead;
tMultiTimer *p1=g_pTimeoutCheckListHead;
if(g_pTimeoutCheckListHead==NULL)
{
return -1;//无定时任务
}
else
{
while(p1->nTimerID != timerID && p1->pNextTimer !=NULL)
{
p2=p1;
p1=p1->pNextTimer;
}
if(p1->nTimerID == timerID)
{
if(p1==g_pTimeoutCheckListHead)
{
g_pTimeoutCheckListHead=p1->pNextTimer;
free(p1);
}
else
{
p2->pNextTimer=p1->pNextTimer;
free(p1);
}
}
else
{
//无指定定时任务
return -1;
}
}
printf(" Tw_destroyTimer end\n");
return 1;
}
VOID Tw_destroyAllTimer(void)
{
tMultiTimer *p2=g_pTimeoutCheckListHead;
tMultiTimer *p1=g_pTimeoutCheckListHead;
while(p1 != NULL)
{
p2 = p1;
p1 = p1->pNextTimer;
free(p2);
p2 = NULL;
}
g_pTimeoutCheckListHead = NULL;
}
int timer_one(HWND hWnd, VOID *data)
{
printf("timer_one\n");
}
int timer_two(HWND hWnd, VOID *data)
{
printf("timer_two\n");
}
int timer_again(HWND hWnd, VOID *data)
{
printf("timer_again\n");
}
int timer_three(HWND hWnd, VOID *data)
{
Tw_destroyAllTimer();
Tw_createTimer(1,1000,timer_again,NULL,0);
printf("timer_three\n");
}
int main(void)
{
int ret = 0;
ret = Tw_InitTimer();
int time1 = Tw_createTimer(1,1000,timer_one,NULL,0);
int time2 = Tw_createTimer(1,3000,timer_two,NULL,0);
int time3 = Tw_createTimer(1,10000,timer_three,NULL,0);
printf(" main :%d,%d,%d\n",ret,time1,time2);
while(1)
{
sleep(1);
printf(" main :\n");
}
return ;
}
结果分析:
预期结果:
实际结果:并不是1s打印一次main
这种情况是因为发送给工作线程的信号中断的主线程的sleep,并且这个中情况只影响主线程而不会影响到其他的工作线程。解决这种问题,最简单的方法是修改这个程序,修改这个线程主线程使用setitimer,工作线程使用sleep。使用函数pthread_sigmask,线程中的信号屏蔽,函数的原型及相关函数为:
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
函数中第一个参数how有三个值SIG_BLOCK、SIG_SETMASK和SIG_UNBLOCK这里我们是用第二个值SIG_SETMASK
int sigemptyset(sigset_t *set); /*清除信号集合set*/
int sigaddset(sigset_t *set, int signum); /*添加信号signum到信号集set中*/
三、多定时器实现二:
tw_timer.c部分代码
void *pthread_func()
{
int ret = Tw_InitTimer();
while(1)
pause();
}
int main(void)
{
int ret = 0;
pthread_t tid;
if(pthread_create(&tid, NULL, pthread_func, NULL) < 0)
{
perror("pthread_create");
return ;
}
//ret = Tw_InitTimer();
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
pthread_sigmask(SIG_SETMASK,&sigset,NULL);
int time1 = Tw_createTimer(1,1000,timer_one,NULL,0);
int time2 = Tw_createTimer(1,3000,timer_two,NULL,0);
int time3 = Tw_createTimer(1,10000,timer_three,NULL,0);
printf(" main :%d,%d,%d\n",ret,time1,time2);
while(1)
{
sleep(1);
printf(" main :\n");
}
return ;
}
运行结果:
上一篇: 你应该去了解的十个PHP框架
推荐阅读
-
Linux服务器实现每天定时备份MySQL数据库的shell脚本
-
html5实现多文件的上传示例代码
-
CentOS7.x使用shell脚本实现使用mysql_multi自动安装MySQL5.7.28多实例
-
Linux Socket 编程简介和实现
-
docker compose linux tomcat 安装(多容器docker) 博客分类: linuxdockercompose dockercomposelinuxtomcat安装
-
PHP+Ajax+JS实现多图上传,ajax多图_PHP教程
-
linux下实现定时执行php脚本_php实例
-
linux使用crontab实现PHP执行计划定时任务
-
如何设置Linux桌面环境 实现HiDPI显示支持的方法
-
SpringBoot Profiles配合Maven Profiles以及Filtering实现多环境下配置切换