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 ;
}

结果分析:

 预期结果:

《Linux多定时器实现》

实际结果:并不是1s打印一次main

《Linux多定时器实现》

       这种情况是因为发送给工作线程的信号中断的主线程的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 ;
}

 运行结果:

《Linux多定时器实现》

 

 

 

 

 

 

 

 

 

    原文作者:@多年以后
    原文地址: https://blog.csdn.net/zdw6868/article/details/107578986
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞