欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux多定时器实现

程序员文章站 2022-06-09 13:07:42
...

一、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多定时器实现

 

 

 

 

 

 

 

 

 

相关标签: C/C++ Linux linux