使用 timerfd + epoll() 實現,簡潔精確。
沒定義 MU_ERROR 宏的話替換為 printf 即可。
mu_timer.h:
#ifndef _MU_TIMER_H_
#define _MU_TIMER_H_#ifdef __cplusplus
extern "C"
{
#endif#include <stdint.h>
#include <time.h>
#include <pthread.h>/*** @brief 定時器狀態*/typedef enum{MU_TIMER_UNINITIALIZED,MU_TIMER_RUNNING,MU_TIMER_PAUSED} TimerStatus;/*** @brief 定時器回調類型*/typedef void (*MuTimerCallback)(void *arg);/*** @brief 定時器結構體*/typedef struct{int timerfd; ///< timerfd文件描述符struct itimerspec tmr; ///< 時間間隔TimerStatus status; ///< 當前狀態int initialized; ///< 是否初始化int counter; ///< 剩余觸發次數(-1為無限次)MuTimerCallback callback; ///< 回調函數void *arg; ///< 回調參數} MuTimer;/*** @brief 初始化定時器管理器** @return int 0成功,-1失敗*/int mu_timer_init(void);/*** @brief 去初始化定時器管理器** @return int 0成功,-1失敗*/int mu_timer_deinit(void);/*** @brief 創建并啟動定時器** @param timer 定時器指針* @param interval 時間間隔* @param callback 回調* @param arg 回調參數* @param trigger_count 觸發次數(-1為無限次)* @return int 0成功,-1失敗* @note* 回調函數應盡量簡潔,避免執行耗時操作,以免影響其他定時器的運行。* 當定時器達到設定的觸發次數后,會自動銷毀,無需手動調用 mu_timer_destroy*/int mu_timer_create(MuTimer *timer, struct timespec interval, MuTimerCallback callback,void *arg, int trigger_count);/*** @brief 暫停定時器** @param timer 定時器指針* @return int 0成功,-1失敗*/int mu_timer_pause(MuTimer *timer);/*** @brief 恢復定時器** @param timer 定時器指針* @return int 0成功,-1失敗*/int mu_timer_resume(MuTimer *timer);/*** @brief 重置定時器時間間隔** @param timer 定時器指針* @return 0成功,-1失敗* @note 若定時器暫停,需恢復后才會計時*/int mu_timer_reset(MuTimer *timer);/*** @brief 設置定時器時間間隔** @param timer 定時器指針* @param interval 時間間隔* @return int 0成功,-1失敗* @note 若定時器暫停,需恢復后才會計時*/int mu_timer_set_interval(MuTimer *timer, struct timespec interval);/*** @brief 銷毀定時器** @param timer 定時器指針* @return int 0成功,-1失敗*/int mu_timer_destroy(MuTimer *timer);#ifdef __cplusplus
}
#endif#endif // _MU_TIMER_H_
mu_timer.c:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <stdint.h>#include "mu_timer.h"
#include "mu_debug.h"#define MAX_EPOLL_EVENTS 32 ///< epoll一次最多處理的事件數// 定時器管理器結構體
typedef struct
{int epfd; // epoll文件描述符pthread_t event_thread; // 事件處理線程pthread_mutex_t mutex; // 管理器互斥鎖int running; // 運行狀態int initialized; // 初始化標記
} MuTimerManager;// 全局管理器實例
static MuTimerManager g_timer_manager = {0};// 規范化timespec
static void normalize_interval(struct timespec *interval)
{if (interval->tv_nsec >= 1000000000L){interval->tv_sec += interval->tv_nsec / 1000000000L;interval->tv_nsec %= 1000000000L;}
}// 處理定時器到期事件
static void handle_timer_expired(MuTimer *timer)
{pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized || timer->status != MU_TIMER_RUNNING){pthread_mutex_unlock(&g_timer_manager.mutex);return;}// 讀取timerfd,清除可讀狀態uint64_t exp;ssize_t s = read(timer->timerfd, &exp, sizeof(uint64_t));if (s != sizeof(uint64_t)){MU_ERROR("read timerfd failed: %s", strerror(errno));{pthread_mutex_unlock(&g_timer_manager.mutex);return;}}// 更新計數器if (timer->counter > 0)timer->counter--;// 執行回調if (timer->callback){pthread_mutex_unlock(&g_timer_manager.mutex);timer->callback(timer->arg);pthread_mutex_lock(&g_timer_manager.mutex);}// 檢查是否需要銷毀定時器if (timer->counter == 0){pthread_mutex_unlock(&g_timer_manager.mutex);mu_timer_destroy(timer);pthread_mutex_lock(&g_timer_manager.mutex);}pthread_mutex_unlock(&g_timer_manager.mutex);
}// 事件處理線程
static void *timer_event_thread(void *arg)
{struct epoll_event events[MAX_EPOLL_EVENTS];while (g_timer_manager.running){int nfds = epoll_wait(g_timer_manager.epfd, events, MAX_EPOLL_EVENTS, 1000); // 1秒超時if (nfds == -1){if (errno == EINTR){continue;}MU_ERROR("epoll_wait failed: %s", strerror(errno));break;}for (int i = 0; i < nfds; i++){if (events[i].events & EPOLLIN){MuTimer *timer = (MuTimer *)events[i].data.ptr;handle_timer_expired(timer);}}}return NULL;
}// 初始化定時器管理器
int mu_timer_init(void)
{if (g_timer_manager.initialized){return -1;}// 創建epoll實例g_timer_manager.epfd = epoll_create1(EPOLL_CLOEXEC);if (g_timer_manager.epfd == -1){MU_ERROR("epoll_create1 failed: %s", strerror(errno));return -1;}// 創建事件處理線程if (pthread_create(&g_timer_manager.event_thread, NULL, timer_event_thread, NULL) != 0){MU_ERROR("pthread_create failed: %s", strerror(errno));close(g_timer_manager.epfd);g_timer_manager.epfd = 0;return -1;}pthread_mutex_init(&g_timer_manager.mutex, NULL);g_timer_manager.running = 1;g_timer_manager.initialized = 1;return 0;
}// 去初始化定時器管理器
int mu_timer_deinit(void)
{if (!g_timer_manager.initialized){return -1;}g_timer_manager.running = 0;// 等待事件處理線程結束pthread_join(g_timer_manager.event_thread, NULL);if (g_timer_manager.epfd > 0){close(g_timer_manager.epfd);}pthread_mutex_destroy(&g_timer_manager.mutex);memset(&g_timer_manager, 0, sizeof(g_timer_manager));return 0;
}int mu_timer_create(MuTimer *timer, struct timespec interval, MuTimerCallback callback,void *arg, int trigger_count)
{if (!timer || !callback || trigger_count == 0 ||interval.tv_sec < 0 || interval.tv_nsec < 0 ||(interval.tv_sec == 0 && interval.tv_nsec == 0) ||!g_timer_manager.initialized)return -1;memset(timer, 0, sizeof(MuTimer));// 創建timerfdtimer->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);if (timer->timerfd == -1){MU_ERROR("timerfd_create failed: %s", strerror(errno));return -1;}normalize_interval(&interval);// 設置timerfdtimer->tmr.it_interval = interval;timer->tmr.it_value = interval;if (timerfd_settime(timer->timerfd, 0, &timer->tmr, NULL) == -1){MU_ERROR("timerfd_settime failed: %s", strerror(errno));close(timer->timerfd);return -1;}timer->callback = callback;timer->arg = arg;timer->counter = trigger_count;timer->status = MU_TIMER_RUNNING;// 添加到epoll監聽struct epoll_event ev;ev.events = EPOLLIN;ev.data.ptr = timer;if (epoll_ctl(g_timer_manager.epfd, EPOLL_CTL_ADD, timer->timerfd, &ev) == -1){MU_ERROR("epoll_ctl ADD failed: %s", strerror(errno));close(timer->timerfd);return -1;}timer->initialized = 1;return 0;
}int mu_timer_pause(MuTimer *timer)
{int ret = 0;if (!g_timer_manager.initialized)return -1;pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized){ret = -1;goto exit;}if (timer->status != MU_TIMER_RUNNING)goto exit;// 獲取剩余時間if (timerfd_gettime(timer->timerfd, &timer->tmr) == -1){MU_ERROR("timerfd_gettime failed: %s", strerror(errno));ret = -1;goto exit;}// 停止timerfdstruct itimerspec its;memset(&its, 0, sizeof(its));if (timerfd_settime(timer->timerfd, 0, &its, NULL) == -1){MU_ERROR("timerfd_settime failed: %s", strerror(errno));ret = -1;goto exit;}timer->status = MU_TIMER_PAUSED;exit:pthread_mutex_unlock(&g_timer_manager.mutex);return ret;
}int mu_timer_resume(MuTimer *timer)
{int ret = 0;if (!g_timer_manager.initialized)return -1;pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized){ret = -1;goto exit;}if (timer->status != MU_TIMER_PAUSED || timer->counter == 0)goto exit;// 重新啟動timerfdif (timerfd_settime(timer->timerfd, 0, &timer->tmr, NULL) == -1){MU_ERROR("timerfd_settime failed: %s", strerror(errno));ret = -1;goto exit;}timer->status = MU_TIMER_RUNNING;exit:pthread_mutex_unlock(&g_timer_manager.mutex);return ret;
}int mu_timer_reset(MuTimer *timer)
{int ret = 0;if (!g_timer_manager.initialized)return -1;pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized){ret = -1;goto exit;}// 重置超時時間timer->tmr.it_value = timer->tmr.it_interval;if (timer->status == MU_TIMER_RUNNING){if (timerfd_settime(timer->timerfd, 0, &timer->tmr, NULL) == -1){MU_ERROR("timerfd_settime failed: %s", strerror(errno));ret = -1;goto exit;}}exit:pthread_mutex_unlock(&g_timer_manager.mutex);return ret;
}int mu_timer_set_interval(MuTimer *timer, struct timespec interval)
{int ret = 0;if (!g_timer_manager.initialized || interval.tv_sec < 0 || interval.tv_nsec < 0 ||(interval.tv_sec == 0 && interval.tv_nsec == 0))return -1;pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized){ret = -1;goto exit;}normalize_interval(&interval);// 重新設置間隔timer->tmr.it_interval = interval;timer->tmr.it_value = interval;if (timer->status == MU_TIMER_RUNNING){if (timerfd_settime(timer->timerfd, 0, &timer->tmr, NULL) == -1){MU_ERROR("timerfd_settime failed: %s", strerror(errno));ret = -1;goto exit;}}exit:pthread_mutex_unlock(&g_timer_manager.mutex);return ret;
}int mu_timer_destroy(MuTimer *timer)
{int ret = 0;if (!g_timer_manager.initialized)return -1;pthread_mutex_lock(&g_timer_manager.mutex);if (!timer || !timer->initialized){ret = -1;goto exit;}// 從epoll中移除if (epoll_ctl(g_timer_manager.epfd, EPOLL_CTL_DEL, timer->timerfd, NULL) == -1){MU_ERROR("epoll_ctl DEL failed: %s", strerror(errno));ret = -1;}close(timer->timerfd);memset(timer, 0, sizeof(MuTimer));exit:pthread_mutex_unlock(&g_timer_manager.mutex);return ret;
}