本文介绍了C linux系统自带的定时器接口使用方法,并封装了接口方便调用,文末有提供示例代码;
示例代码演示为创建两个定时器,使用同一个回调函数,在回调函数中用创建传入的时间ID区分不同的定时器事件。
定时器A为循环触发2s触发一次,定时器B为循环触发 4s触发一次。
注:编译示例代码时需要链接-lrt -lpthread这两个库,lrt为定时器需要,-lpthread为示例sem信号量相关接口需要
需要包含的头文件
#include <signal.h>
#include <time.h>
结构体和枚举
/* 定时器类型枚举 */
typedef enum
{
/* 循环触发定时器 */
MY_CYCLE_TIMER = 0,
/* 只触发一次定时器 */
MY_ONCE_TIMER = 1,
} MyTimerType_E;
/* 定时器事件类型枚举 */
typedef enum
{
/* A事件 */
MY_TIMER_A_EVENT = 0,
/* B事件 */
MY_TIMER_B_EVENT = 1,
} MyTimerEventType_E;
#if 0
/* 系统自带结构体,在此当注释方便开发理解 */
union sigval
{
/* integer value */
int sival_int;
/* pointer value */
void *sival_ptr;
}
#endif
typedef void (*timerCallBcak)(union sigval v);
接口实现
创建定时器接口
/*!
* @brief 创建定时器
* @details 创建定时器
* @param[In] cb 定时器回调函数
* @param[In] event 定时器事件ID
* @return 返回值说明
* @retval 返回创建的定时器ID 创建失败返回-1
*/
timer_t MyCreateTimer(timerCallBcak cb, MyTimerEventType_E event)
{
int ret = 0;
struct sigevent sTimer;
timer_t timerId;
memset(&sTimer, 0, sizeof(struct sigevent));
/* 这个值作为定时器回调参数传入,也可以传入指针,此处用来区分定时器事件 */
sTimer.sigev_value.sival_int = event;
sTimer.sigev_notify = SIGEV_THREAD;
sTimer.sigev_notify_function = cb;
ret = timer_create(CLOCK_REALTIME, &sTimer, &timerId);
if (-1 == ret)
{
printf("fail to timer_create!\n");
return NULL;
}
return timerId;
}
启动定时器接口
/*!
* @brief 启动定时器
* @details 启动定时器
* @param[In] timerId 定时器ID
* @param[In] timeout 超时时间 单位为秒
* @param[In] timerType 定时器类型
* @return 返回值说明
* @retval 0启动成功 -1启动失败
*/
int MyStartTimer(timer_t timerId, int timeout, MyTimerType_E timerType)
{
struct itimerspec timerInterval;
int ret = 0;
memset(&timerInterval, 0x0, sizeof(struct itimerspec));
timerInterval.it_value.tv_sec = timeout;
timerInterval.it_value.tv_nsec = 0;
if (MY_CYCLE_TIMER == timerType)
{
timerInterval.it_interval = timerInterval.it_value;
}
ret = timer_settime(timerId, 0, &timerInterval, NULL);
if (-1 == ret)
{
printf("fail to Liot_startTimer\n");
return ret;
}
return 0;
}
停止定时器接口
/*!
* @brief 停止定时器
* @details 停止定时器
* @param[In] timerId 定时器ID
* @return 返回值说明
* @retval 0停止成功 -1停止失败
*/
int MyStopTimer(timer_t timerId)
{
struct itimerspec timerInterval;
int ret = 0;
memset(&timerInterval, 0x0, sizeof(struct itimerspec));
ret = timer_settime(timerId, 0, &timerInterval, NULL);
if (-1 == ret)
{
printf("fail to Liot_stopTimer\n");
return ret;
}
return 0;
}
销毁定时器接口
/*!
* @brief 销毁定时器
* @details 销毁定时器
* @param[In] timerId 定时器ID
* @return 返回值说明
* @retval void
*/
void MyDeleteTimer(timer_t timerId)
{
timer_delete(timerId);
}
示例代码
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <string.h>
/* 定时器类型枚举 */
typedef enum
{
/* 循环触发定时器 */
MY_CYCLE_TIMER = 0,
/* 只触发一次定时器 */
MY_ONCE_TIMER = 1,
} MyTimerType_E;
/* 定时器事件类型枚举 */
typedef enum
{
/* A事件 */
MY_TIMER_A_EVENT = 0,
/* B事件 */
MY_TIMER_B_EVENT = 1,
} MyTimerEventType_E;
#if 0
/* 系统自带结构体,在此当注释方便开发理解 */
union sigval
{
/* integer value */
int sival_int;
/* pointer value */
void *sival_ptr;
}
#endif
typedef void (*timerCallBcak)(union sigval v);
/* 定时器A的ID */
static timer_t g_s_myTimerIdA;
/* 定时器B的ID */
static timer_t g_s_myTimerIdB;
static sem_t g_s_mySem;
/*!
* @brief 创建定时器
* @details 创建定时器
* @param[In] cb 定时器回调函数
* @param[In] event 定时器事件ID
* @return 返回值说明
* @retval 返回创建的定时器ID 创建失败返回-1
*/
timer_t MyCreateTimer(timerCallBcak cb, MyTimerEventType_E event)
{
int ret = 0;
struct sigevent sTimer;
timer_t timerId;
memset(&sTimer, 0, sizeof(struct sigevent));
/* 这个值作为定时器回调参数传入,也可以传入指针,此处用来区分定时器事件 */
sTimer.sigev_value.sival_int = event;
sTimer.sigev_notify = SIGEV_THREAD;
sTimer.sigev_notify_function = cb;
ret = timer_create(CLOCK_REALTIME, &sTimer, &timerId);
if (-1 == ret)
{
printf("fail to timer_create!\n");
return NULL;
}
return timerId;
}
/*!
* @brief 启动定时器
* @details 启动定时器
* @param[In] timerId 定时器ID
* @param[In] timeout 超时时间 单位为秒
* @param[In] timerType 定时器类型
* @return 返回值说明
* @retval 0启动成功 -1启动失败
*/
int MyStartTimer(timer_t timerId, int timeout, MyTimerType_E timerType)
{
struct itimerspec timerInterval;
int ret = 0;
memset(&timerInterval, 0x0, sizeof(struct itimerspec));
timerInterval.it_value.tv_sec = timeout;
timerInterval.it_value.tv_nsec = 0;
if (MY_CYCLE_TIMER == timerType)
{
timerInterval.it_interval = timerInterval.it_value;
}
ret = timer_settime(timerId, 0, &timerInterval, NULL);
if (-1 == ret)
{
printf("fail to Liot_startTimer\n");
return ret;
}
return 0;
}
/*!
* @brief 停止定时器
* @details 停止定时器
* @param[In] timerId 定时器ID
* @return 返回值说明
* @retval 0停止成功 -1停止失败
*/
int MyStopTimer(timer_t timerId)
{
struct itimerspec timerInterval;
int ret = 0;
memset(&timerInterval, 0x0, sizeof(struct itimerspec));
ret = timer_settime(timerId, 0, &timerInterval, NULL);
if (-1 == ret)
{
printf("fail to Liot_stopTimer\n");
return ret;
}
return 0;
}
/*!
* @brief 销毁定时器
* @details 销毁定时器
* @param[In] timerId 定时器ID
* @return 返回值说明
* @retval void
*/
void MyDeleteTimer(timer_t timerId)
{
timer_delete(timerId);
}
void MyTimerCallback(union sigval v)
{
static int i = 0;
time_t t = time(NULL);
struct tm *dateTime = localtime(&t);
char *date = asctime(dateTime);
if (MY_TIMER_A_EVENT == v.sival_int)
{
printf("AAAAAtimer is coming! date:%s\n", date);
}
else if (MY_TIMER_B_EVENT == v.sival_int)
{
printf("BBBBBtimer is coming! date:%s\n", date);
}
i++;
if (i >= 6)
{
MyStopTimer(g_s_myTimerIdA);
MyStopTimer(g_s_myTimerIdB);
sem_post(&g_s_mySem);
}
}
int main()
{
sem_init(&g_s_mySem, 0, 0);
g_s_myTimerIdA = MyCreateTimer(MyTimerCallback, MY_TIMER_A_EVENT);
g_s_myTimerIdB = MyCreateTimer(MyTimerCallback, MY_TIMER_B_EVENT);
MyStartTimer(g_s_myTimerIdA, 2, MY_CYCLE_TIMER);
MyStartTimer(g_s_myTimerIdB, 4, MY_CYCLE_TIMER);
printf("wait timer stop\n");
sem_wait(&g_s_mySem);
printf("timer stop\n");
MyDeleteTimer(g_s_myTimerIdA);
MyDeleteTimer(g_s_myTimerIdB);
g_s_myTimerIdA = NULL;
g_s_myTimerIdB = NULL;
return 0;
}
运行结果
./a.out
wait timer stop
AAAAAtimer is coming! date:Thu Sep 29 08:22:00 2022
AAAAAtimer is coming! date:Thu Sep 29 08:22:02 2022
BBBBBtimer is coming! date:Thu Sep 29 08:22:02 2022
AAAAAtimer is coming! date:Thu Sep 29 08:22:04 2022
AAAAAtimer is coming! date:Thu Sep 29 08:22:06 2022
BBBBBtimer is coming! date:Thu Sep 29 08:22:06 2022
timer stop