計時器是事件驅動系統的心跳。本文呈現一個毫秒級精度、跨平台、執行緒安全的 C 計時器庫 sctimer,採用升序鏈表管理定時事件,支援一次性/週期性、同步/非同步模式,並提供完整建構/銷毀介面。
// 新增計時器 // start: 延遲啟動(ms),0=立即 // cut: 執行次數,0=永久,1=一次 // intval: 間隔(ms) // timer: 回呼函式 void(*)(void*) // arg: 回呼參數 // fb: 0=同步(在計時器執行緒), 1=非同步(建立新執行緒) // 回傳: 計時器唯一 ID int st_add(int start, int cut, int intval, vdel_f timer, void *arg, bool fb); // 刪除計時器 inline void st_del(int timer_id);
// 1 秒後同步執行一次 st_add(1000, 1, 0, callback, arg, false); // 立即啟動,每 200ms 非同步執行,永久 st_add(0, 0, 200, callback, arg, true);
// 定時器節點
struct stnode {
int id; // 唯一 ID
time_t stime; // 觸發秒數
int ms; | 毫秒餘數
int cut; // 剩餘執行次數 (-1=永久)
int intval; // 間隔
int type; // 0=同步, 1=非同步
vdel_f timer; // 回呼
void *arg; // 參數
struct stnode *next;
};
// 管理器(單例)
struct stlist {
int lock; // 原子鎖
int nowid; // ID 分配器
int status; // 0=停止, 1=運行
pthread_t tid; // 主迴圈執行緒
struct stnode *head; // 升序鏈表頭
} _st;
_stlist_add(保持升序)static bool _stlist_add(struct stlist *st, struct stnode *node) {
if (!st->head || _stnode_cmp(node, st->head)) {
node->next = st->head;
st->head = node;
return true; // 新頭節點,需喚醒主迴圈
}
struct stnode *cur = st->head;
while (cur->next && !_stnode_cmp(node, cur->next))
cur = cur->next;
node->next = cur->next;
cur->next = node;
return false;
}
_stlist_loopstatic void *_stlist_loop(struct stlist *st) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_detach(pthread_self());
while (st->head) {
pthread_testcancel();
int wait_ms = _sleeptime(st); // 計算至頭節點觸發的毫秒數
if (wait_ms <= 0 || st->head->cut == 1)
_slnode_again_run(st); // 觸發執行並重新排程
else
SLEEPMS(wait_ms); // 精確睡眠
}
st->status = 0;
return NULL;
}
_slnode_again_runcut == 1:釋放節點(一次性任務結束)cut > 1:cut--,更新觸發時間,重新插入鏈表cut == 0(永久):更新時間,重新插入schead.husleep(ms*1000) / Windows Sleep(ms)gettimeofday / Windows 以 GetLocalTime 實作__sync_lock_test_and_set / __sync_lock_release + usleep 自旋InterlockedExchange / InterlockedExchangeAdd + Sleep(0) 讓權CERR/CERR_EXIT、陣列長度 LEN、浮點比較 EQ_FLOAT、除錯碼 DEBUG_CODE、暫停 INIT_PAUSEscatom.h// GCC 版本
#define ATOM_LOCK(v) \
while(ATOM_SET(v, 1)) usleep(2)
#define ATOM_UNLOCK(v) \
__sync_lock_release(&(v))
// MSVC 版本
#define ATOM_LOCK(v) \
while(ATOM_SET(v, 1)) Sleep(0)
#define ATOM_UNLOCK(v) \
ATOM_SET(v, 0)
int main() {
st_add(0, 5, 2000, timer, (void*)1, false); // 同步,5次,2秒間隔
st_add(3000, 2, 2000, timer, (void*)2, false); // 延遲3秒啟動
st_add(4000, 1, 2000, timer, (void*)3, false); // 一次性
int tid = st_add(0, 0, 1000, timer, (void*)4, true); // 非同步永久
SLEEPMS(5000);
st_del(tid); // 取消永久計時器
st_add(100, 0, 5000, timer, (void*)5, false);
sh_pause(); // 除錯模式暫停
return 0;
}
Linux/Windows 雙平台編譯通過,輸出顯示計時器精確觸發、非同步執行緒正常建構/銷毀。
schead.h/c:跨平台基礎設施scatom.h:原子鎖sctimer.h/c:計時器核心test_sctimer.c:測試程式Makefile:建構腳本epoll/kqueue/IOCP 實現單執行緒事件迴圈timerfd/CreateTimerQueueTimer)本實作展示了系統級計時器的核心設計:有序資料結構、精確睡眠喚醒、同步/非同步靈活切換、跨平台抽象、原子操作保護共享狀態。程式碼結構清晰,適合嵌入式、伺服器、遊戲引擎等場景直接整合或二次開發。