C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹
定時(shí)器
有些時(shí)候我們需要延遲執(zhí)行一些功能,比如每10s進(jìn)行一次數(shù)據(jù)采集?;蛘吒嬷脩艏寄芾鋮s有多少時(shí)間,如果我們將執(zhí)行這些功能的任務(wù)交給主線程,就會(huì)造成主線程的阻塞。因此我們可以選擇一個(gè)創(chuàng)建一個(gè)子線程,讓其檢測(cè)定時(shí)器中的任務(wù),當(dāng)有任務(wù)的時(shí)間到了的時(shí)候,就去執(zhí)行這個(gè)任務(wù)。
最小堆實(shí)現(xiàn)定時(shí)器
定時(shí)器可以由很多種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn),比如最小堆、紅黑樹、跳表、甚至數(shù)組都可以,其本質(zhì)都是拿到最小時(shí)間的任務(wù),然后取出該任務(wù)并執(zhí)行。
綜合實(shí)現(xiàn)難度和效率來看,最小堆是最容易實(shí)現(xiàn)定時(shí)器的數(shù)據(jù)結(jié)構(gòu)。
最小堆主要有以下接口:
#pragma once
#include <vector>
#include <map>
using namespace std;
typedef void (*TimerHandler)(struct TimerNode *node);
//獲取系統(tǒng)時(shí)間,單位是毫秒
static uint32_t current_time()
{
uint32_t t;
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint32_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;
return t;
}
struct TimerNode
{
//該任務(wù)在最小堆中的下標(biāo)位置
int idx = 0;
//該任務(wù)是第幾號(hào)任務(wù)
int id = 0;
//幾毫秒后執(zhí)行該任務(wù)
unsigned int expire = 0;
//回調(diào)函數(shù)
TimerHandler cb = NULL;
};
class MinHeapTimer
{
public:
MinHeapTimer()
{
_heap.clear();
_map.clear();
}
int Count();
//加入任務(wù),expire為該任務(wù)的失效時(shí)間,expire過后就要執(zhí)行回調(diào)函數(shù)cb
int AddTimer(uint32_t expire, TimerHandler cb);
//刪除一個(gè)任務(wù)
bool DelTimer(int id);
//獲取一個(gè)任務(wù)
void ExpireTimer();
private:
//用于比較兩個(gè)任務(wù)的過期時(shí)間
bool _compare(int lhs, int rhs);
//向下調(diào)整算法,每次刪除一個(gè)節(jié)點(diǎn)就要向下調(diào)整
void _shiftDown(int parent);
//向上調(diào)整算法,每添加一個(gè)數(shù)都要調(diào)用向上調(diào)整算法,保證根節(jié)點(diǎn)為最小節(jié)點(diǎn)
void _shiftUp(int child);
//刪除的子函數(shù)
void _delNode(TimerNode *node);
void resign(int pos);
private:
//數(shù)組中存儲(chǔ)任務(wù)節(jié)點(diǎn)
vector<TimerNode *> _heap;
//存儲(chǔ)值和響應(yīng)節(jié)點(diǎn)的映射關(guān)系
map<int, TimerNode *> _map;
//任務(wù)的個(gè)數(shù),注意不是_heap的size
int _count = 0;
};具體的實(shí)現(xiàn)以及測(cè)試為:
#pragma once
#include <vector>
#include <map>
using namespace std;
typedef void (*TimerHandler)(struct TimerNode *node);
//獲取系統(tǒng)時(shí)間,單位是毫秒
static uint32_t current_time()
{
uint32_t t;
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint32_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;
return t;
}
struct TimerNode
{
//該任務(wù)在最小堆中的下標(biāo)位置
int idx = 0;
//該任務(wù)是第幾號(hào)任務(wù)
int id = 0;
unsigned int expire = 0;
//回調(diào)函數(shù)
TimerHandler cb = NULL;
};
class MinHeapTimer
{
public:
MinHeapTimer()
{
_heap.clear();
_map.clear();
}
int Count()
{
return ++_count;
}
//加入任務(wù),expire為該任務(wù)的失效時(shí)間,expire過后就要執(zhí)行回調(diào)函數(shù)cb
int AddTimer(uint32_t expire, TimerHandler cb)
{
int64_t timeout = current_time() + expire;
TimerNode *node = new TimerNode;
int id = Count();
node->id = id;
node->expire = timeout;
node->cb = cb;
node->idx = (int)_heap.size();
_heap.push_back(node);
_shiftUp((int)_heap.size() - 1);
_map.insert(make_pair(id, node));
return id;
}
//刪除一個(gè)任務(wù)
bool DelTimer(int id)
{
auto iter = _map.find(id);
if (iter == _map.end())
return false;
_delNode(iter->second);
return true;
}
//獲取一個(gè)任務(wù)
void ExpireTimer()
{
if (_heap.empty())
{
return;
}
//獲取當(dāng)前時(shí)間
uint32_t now = current_time();
while (!_heap.empty())
{
//獲取最近的一個(gè)任務(wù)
TimerNode *node = _heap.front();
//當(dāng)最近一個(gè)任務(wù)的時(shí)間大于當(dāng)前時(shí)間,說明沒有任務(wù)要執(zhí)行
if (now < node->expire)
{
break;
}
//遍歷一下堆,這一步可以不加
for (int i = 0; i < _heap.size(); i++)
{
std::cout << "touch idx: " << _heap[i]->idx
<< " id: " << _heap[i]->id << " expire: "
<< _heap[i]->expire << std::endl;
}
//執(zhí)行最近任務(wù)的回調(diào)函數(shù)
if (node->cb)
{
node->cb(node);
}
//執(zhí)行完就刪掉這個(gè)任務(wù)
_delNode(node);
}
}
private:
//用于比較兩個(gè)任務(wù)的過期時(shí)間
bool _compare(int lhs, int rhs)
{
return _heap[lhs]->expire < _heap[rhs]->expire;
}
//向下調(diào)整算法,每次刪除一個(gè)節(jié)點(diǎn)就要向下調(diào)整
void _shiftDown(int parent)
{
int child = parent * 2 + 1;
while (child < _heap.size() - 1)
{
if (child + 1 < _heap.size() - 1 && !_compare(child, child + 1))
{
child++;
}
if (!_compare(parent, child))
{
std::swap(_heap[parent], _heap[child]);
_heap[parent]->idx = parent;
_heap[child]->idx = child;
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//向上調(diào)整算法,每添加一個(gè)數(shù)都要調(diào)用向上調(diào)整算法,保證根節(jié)點(diǎn)為最小節(jié)點(diǎn)
void _shiftUp(int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (!_compare(parent, child))
{
std::swap(_heap[parent], _heap[child]);
_heap[parent]->idx = parent;
_heap[child]->idx = child;
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
//刪除的子函數(shù)
void _delNode(TimerNode *node)
{
int last = (int)_heap.size() - 1;
int idx = node->idx;
if (idx != last)
{
std::swap(_heap[idx], _heap[last]);
_heap[idx]->idx = idx;
resign(idx);
}
_heap.pop_back();
_map.erase(node->id);
delete node;
}
void resign(int pos)
{
//向上調(diào)整和向下調(diào)整只會(huì)發(fā)生一個(gè)
_shiftDown(pos);
_shiftUp(pos);
}
private:
//數(shù)組中存儲(chǔ)任務(wù)節(jié)點(diǎn)
vector<TimerNode *> _heap;
//存儲(chǔ)值和響應(yīng)節(jié)點(diǎn)的映射關(guān)系
map<int, TimerNode *> _map;
//任務(wù)的個(gè)數(shù),注意不是_heap的size
int _count = 0;
};#include <time.h>
#include <unistd.h>
#include <iostream>
#include "minheap.h"
void print_hello(TimerNode *te)
{
std::cout << "hello world time = " << te->idx << "\t" << te->id << "\t" << current_time() << std::endl;
}
int main()
{
MinHeapTimer mht;
//一號(hào)任務(wù),立刻執(zhí)行
mht.AddTimer(0, print_hello);
//二號(hào)任務(wù),一秒后執(zhí)行
mht.AddTimer(1000, print_hello);
mht.AddTimer(7000, print_hello);
mht.AddTimer(2000, print_hello);
mht.AddTimer(9000, print_hello);
mht.AddTimer(10000, print_hello);
mht.AddTimer(6000, print_hello);
mht.AddTimer(3000, print_hello);
while (1)
{
mht.ExpireTimer();
// usleep(10000);
sleep(1);
}
return 0;
}
時(shí)間輪
上面的定時(shí)器在任務(wù)數(shù)量很多時(shí),效率會(huì)很低,因?yàn)槲覀冃枰米钚《褋砭S護(hù)這些任務(wù),并且每刪除一個(gè)任務(wù),都要進(jìn)行調(diào)整。其主要原因是我們不知道其他任務(wù)什么時(shí)候執(zhí)行,所以我們只能進(jìn)行調(diào)整,將最近的任務(wù)放到堆頂。
如果我們能夠向哈希桶那樣,將要執(zhí)行的任務(wù)形成鏈表,掛到要執(zhí)行的位置,當(dāng)時(shí)間走到那個(gè)位置的時(shí)候,就執(zhí)行這些任務(wù),效率豈不是更高?

單層級(jí)時(shí)間輪
客戶端每 5 秒鐘發(fā)送?跳包;服務(wù)端若 10 秒內(nèi)沒收到?跳數(shù)據(jù),則清除連接。
考慮到正常情況下 5 秒鐘發(fā)送?次?跳包,10 秒才檢測(cè)?次,如下圖到索引為 10 的時(shí)候并不能踢掉連接;所以需要每收到?次?跳包則 used++ ,每檢測(cè)?次 used-- ;當(dāng)檢測(cè)到used == 0 則踢掉連接;

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#define MAX_CONN ((1 << 16) - 1)
//連接的節(jié)點(diǎn),用來記錄心跳包發(fā)送的次數(shù)
typedef struct conn_node
{
struct conn_node *next;
//引用計(jì)數(shù)的次數(shù),當(dāng)used==0,相當(dāng)于自動(dòng)銷毀
uint8_t used;
int id;
} conn_node_t;
//用數(shù)組記錄所有的連接
static conn_node_t nodes[MAX_CONN] = {0};
static uint32_t iter = 0;
//獲取一個(gè)空的連接節(jié)點(diǎn)
conn_node_t *get_node()
{
iter++;
while (nodes[iter & MAX_CONN].used > 0)
{
iter++;
}
return &nodes[iter];
}
//哈希桶的個(gè)數(shù)
#define TW_SIZE 16
//檢測(cè)心跳包的延遲時(shí)間,由于哈希桶的個(gè)數(shù)有限,所以心跳包發(fā)送時(shí)間不能夠超過6
#define EXPIRE 10
//取余操作
#define TW_MASK (TW_SIZE - 1)
static uint32_t tick = 0;
//哈希桶
typedef struct link_list
{
conn_node_t head;
//一個(gè)tail,能夠進(jìn)行快速插入
conn_node_t *tail;
} link_list_t;
//添加連接
void add_conn(link_list_t *tw, conn_node_t *node, int delay)
{
//獲取對(duì)應(yīng)的哈希桶
link_list_t *list = &tw[(tick + EXPIRE + delay) & TW_MASK];
list->tail->next = node;
list->tail = node;
node->next = NULL;
node->used++;
}
//清楚這個(gè)哈希桶
void link_clear(link_list_t *list)
{
list->head.next = NULL;
list->tail = &(list->head);
}
//檢測(cè)哈希桶
void check_conn(link_list_t *tw)
{
int32_t itick = tick;
tick++;
//取到對(duì)應(yīng)哈希桶的鏈表
link_list_t *list = &tw[itick & TW_MASK];
//檢測(cè)哈希桶對(duì)應(yīng)的鏈表
conn_node_t *current = list->head.next;
while (current)
{
conn_node_t *temp = current;
current = current->next;
temp->used--;
if (temp->used == 0)
{
printf("連接:%d 斷開\n", temp->id);
temp->next = NULL;
continue;
}
printf("這個(gè)鏈接:%d 心跳包還剩:%d個(gè)需要檢測(cè)\n", temp->id, temp->used);
}
link_clear(list);
}
//獲取時(shí)間,單位是s
static time_t current_time()
{
time_t t;
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (time_t)ti.tv_sec;
return t;
}
int main()
{
memset(nodes, 0, MAX_CONN * sizeof(conn_node_t));
// init link list
link_list_t tw[TW_SIZE];
memset(tw, 0, TW_SIZE * sizeof(link_list_t));
for (int i = 0; i < TW_SIZE; i++)
{
link_clear(&tw[i]);
}
// 第一個(gè)連接對(duì)應(yīng)的心跳包,在0和5時(shí)進(jìn)行發(fā)送
//所以會(huì)在10s和15s時(shí)進(jìn)行檢測(cè),15s時(shí)把該連接斷開
{
conn_node_t *node = get_node();
node->id = 10001;
add_conn(tw, node, 0);
add_conn(tw, node, 5);
}
//第二個(gè)連接發(fā)送的心跳包,在第10s時(shí)進(jìn)行檢測(cè)
{
conn_node_t *node = get_node();
node->id = 10002;
add_conn(tw, node, 0);
}
//第二個(gè)連接發(fā)送的心跳包,在第13s時(shí)檢測(cè)
{
conn_node_t *node = get_node();
node->id = 10003;
add_conn(tw, node, 3);
}
time_t start = current_time();
while (1)
{
time_t now = current_time();
if (now - start > 0)
{
for (int i = 0; i < now - start; i++)
check_conn(tw);
start = now;
printf("在第%d秒時(shí)檢測(cè),此時(shí)機(jī)器時(shí)間:%d\n", tick, now);
}
}
return 0;
}
上面的時(shí)間輪受哈希桶大小和延遲10s收到心跳包的影響,只能在[0,6]秒內(nèi)發(fā)送數(shù)據(jù)心跳包,如果想要延遲長(zhǎng)時(shí)間,則需要擴(kuò)大哈希桶的大小。
如果我們不發(fā)送心跳包,而是改成在若干秒后執(zhí)行一個(gè)任務(wù),比如50s后執(zhí)行任務(wù),但哈希桶大小只有16,我們可以在任務(wù)節(jié)點(diǎn)中增加一個(gè)參數(shù)round,用來記錄需要走多少遍哈希桶,比如50s,對(duì)應(yīng)到大小為16的哈希桶則round=3,idx=2。
不過這樣做,在check_conn取任務(wù)時(shí)就不能夠把整個(gè)鏈表都取出來,而是需要取出round==0的任務(wù)。
typedef struct node
{
struct conn_node *next;
//需要走多少輪哈希桶,當(dāng)round==0時(shí),則說明需要執(zhí)行這個(gè)任務(wù)
int round;
int id;
} node_t;這樣做能解決時(shí)間輪刻度范圍過大造成的空間浪費(fèi),但是卻帶來了另一個(gè)問題:時(shí)間輪每次都需要遍歷任務(wù)列表,耗時(shí)增加,當(dāng)時(shí)間輪刻度粒度很小(秒級(jí)甚至毫秒級(jí)),任務(wù)列表又特別長(zhǎng)時(shí),這種遍歷的辦法是不可接受的。
多層級(jí)時(shí)間輪
參照時(shí)鐘表盤的運(yùn)轉(zhuǎn)規(guī)律,可以將定時(shí)任務(wù)根據(jù)觸發(fā)的緊急程度,分布到不同層級(jí)的時(shí)間輪中;
假設(shè)時(shí)間精度為 10ms ;在第 1 層級(jí)每 10ms 移動(dòng)?格;每移動(dòng)?格執(zhí)?該格?當(dāng)中所有的定時(shí)任務(wù);
當(dāng)?shù)?1 層指針從 255 格開始移動(dòng),此時(shí)層級(jí) 2 移動(dòng)?格;層級(jí) 2 移動(dòng)?格的?為定義為,將該格當(dāng)中的定時(shí)任務(wù)重新映射到層級(jí) 1 當(dāng)中;同理,層級(jí) 2 當(dāng)中從 63 格開始移動(dòng),層級(jí) 3 格?中的定時(shí)任務(wù)重新映射到層級(jí) 2 ; 以此類推層級(jí) 4 往層級(jí) 3 映射,層級(jí) 5 往層級(jí) 4 映射。
只有任務(wù)在第一層時(shí)才會(huì)被執(zhí)行,其他層都是將任務(wù)重新映射到上一層。

timewheel.h:
#pragma once
#include <stdint.h>
#define TIME_NEAR_SHIFT 8
#define TIME_NEAR (1 << TIME_NEAR_SHIFT)
#define TIME_LEVEL_SHIFT 6
#define TIME_LEVEL (1 << TIME_LEVEL_SHIFT)
#define TIME_NEAR_MASK (TIME_NEAR - 1)
#define TIME_LEVEL_MASK (TIME_LEVEL - 1)
typedef struct timer_node timer_node_t;
typedef void (*handler_pt)(struct timer_node *node);
struct timer_node
{
struct timer_node *next;
uint32_t expire; //時(shí)間
handler_pt callback; //回調(diào)函數(shù)
uint8_t cancel; //是否刪除
int id; // 此時(shí)攜帶參數(shù)
};
timer_node_t *add_timer(int time, handler_pt func, int threadid);
void expire_timer(void);
void del_timer(timer_node_t *node);
void init_timer(void);
void clear_timer();spinlock.h:
#pragma once
struct spinlock
{
int lock;
};
void spinlock_init(struct spinlock *lock)
{
lock->lock = 0;
}
void spinlock_lock(struct spinlock *lock)
{
while (__sync_lock_test_and_set(&lock->lock, 1))
{
}
}
int spinlock_trylock(struct spinlock *lock)
{
return __sync_lock_test_and_set(&lock->lock, 1) == 0;
}
void spinlock_unlock(struct spinlock *lock)
{
__sync_lock_release(&lock->lock);
}
void spinlock_destroy(struct spinlock *lock)
{
(void)lock;
}timewheel.cpp:
#include "spinlock.h"
#include "timewheel.h"
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
typedef struct link_list
{
timer_node_t head;
timer_node_t *tail;
} link_list_t;
//多級(jí)時(shí)間輪
typedef struct timer
{
//第一級(jí)
link_list_t near[TIME_NEAR];
// 2-4級(jí)
link_list_t t[4][TIME_LEVEL];
struct spinlock lock;
uint32_t time;
uint64_t current;
uint64_t current_point;
} s_timer_t;
static s_timer_t *TI = NULL;
timer_node_t *link_clear(link_list_t *list)
{
timer_node_t *ret = list->head.next;
list->head.next = 0;
list->tail = &(list->head);
return ret;
}
//鏈接一個(gè)節(jié)點(diǎn)
void link(link_list_t *list, timer_node_t *node)
{
list->tail->next = node;
list->tail = node;
node->next = 0;
}
void add_node(s_timer_t *T, timer_node_t *node)
{
uint32_t time = node->expire;
uint32_t current_time = T->time;
uint32_t msec = time - current_time;
//根據(jù)時(shí)間
if (msec < TIME_NEAR)
{ //[0, 0x100)
link(&T->near[time & TIME_NEAR_MASK], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + TIME_LEVEL_SHIFT)))
{ //[0x100, 0x4000)
link(&T->t[0][((time >> TIME_NEAR_SHIFT) & TIME_LEVEL_MASK)], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + 2 * TIME_LEVEL_SHIFT)))
{ //[0x4000, 0x100000)
link(&T->t[1][((time >> (TIME_NEAR_SHIFT + TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + 3 * TIME_LEVEL_SHIFT)))
{ //[0x100000, 0x4000000)
link(&T->t[2][((time >> (TIME_NEAR_SHIFT + 2 * TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
else
{ //[0x4000000, 0xffffffff]
link(&T->t[3][((time >> (TIME_NEAR_SHIFT + 3 * TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
}
//增加事件
timer_node_t *add_timer(int time, handler_pt func, int threadid)
{
timer_node_t *node = (timer_node_t *)malloc(sizeof(*node));
spinlock_lock(&TI->lock);
node->expire = time + TI->time; // 每10ms加1 0
node->callback = func;
node->id = threadid;
if (time <= 0)
{
node->callback(node);
free(node);
spinlock_unlock(&TI->lock);
return NULL;
}
add_node(TI, node);
spinlock_unlock(&TI->lock);
return node;
}
void move_list(s_timer_t *T, int level, int idx)
{
timer_node_t *current = link_clear(&T->t[level][idx]);
while (current)
{
timer_node_t *temp = current->next;
add_node(T, current);
current = temp;
}
}
void timer_shift(s_timer_t *T)
{
int mask = TIME_NEAR;
uint32_t ct = ++T->time;
if (ct == 0)
{
move_list(T, 3, 0);
}
else
{
// ct / 256
uint32_t time = ct >> TIME_NEAR_SHIFT;
int i = 0;
// ct % 256 == 0
while ((ct & (mask - 1)) == 0)
{
int idx = time & TIME_LEVEL_MASK;
if (idx != 0)
{
move_list(T, i, idx);
break;
}
mask <<= TIME_LEVEL_SHIFT;
time >>= TIME_LEVEL_SHIFT;
++i;
}
}
}
void dispatch_list(timer_node_t *current)
{
do
{
timer_node_t *temp = current;
current = current->next;
if (temp->cancel == 0)
temp->callback(temp);
free(temp);
} while (current);
}
void timer_execute(s_timer_t *T)
{
int idx = T->time & TIME_NEAR_MASK;
while (T->near[idx].head.next)
{
timer_node_t *current = link_clear(&T->near[idx]);
spinlock_unlock(&T->lock);
dispatch_list(current);
spinlock_lock(&T->lock);
}
}
void timer_update(s_timer_t *T)
{
spinlock_lock(&T->lock);
timer_execute(T);
timer_shift(T);
timer_execute(T);
spinlock_unlock(&T->lock);
}
void del_timer(timer_node_t *node)
{
node->cancel = 1;
}
s_timer_t *timer_create_timer()
{
s_timer_t *r = (s_timer_t *)malloc(sizeof(s_timer_t));
memset(r, 0, sizeof(*r));
int i, j;
for (i = 0; i < TIME_NEAR; i++)
{
link_clear(&r->near[i]);
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < TIME_LEVEL; j++)
{
link_clear(&r->t[i][j]);
}
}
spinlock_init(&r->lock);
r->current = 0;
return r;
}
uint64_t gettime()
{
uint64_t t;
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint64_t)ti.tv_sec * 100;
t += ti.tv_nsec / 10000000;
return t;
}
void expire_timer(void)
{
uint64_t cp = gettime();
if (cp != TI->current_point)
{
uint32_t diff = (uint32_t)(cp - TI->current_point);
TI->current_point = cp;
int i;
for (i = 0; i < diff; i++)
{
timer_update(TI);
}
}
}
void init_timer(void)
{
TI = timer_create_timer();
TI->current_point = gettime();
}
void clear_timer()
{
int i, j;
for (i = 0; i < TIME_NEAR; i++)
{
link_list_t *list = &TI->near[i];
timer_node_t *current = list->head.next;
while (current)
{
timer_node_t *temp = current;
current = current->next;
free(temp);
}
link_clear(&TI->near[i]);
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < TIME_LEVEL; j++)
{
link_list_t *list = &TI->t[i][j];
timer_node_t *current = list->head.next;
while (current)
{
timer_node_t *temp = current;
current = current->next;
free(temp);
}
link_clear(&TI->t[i][j]);
}
}
}tw-timer.cpp:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include "timewheel.h"
struct context
{
int quit;
int thread;
};
struct thread_param
{
struct context *ctx;
int id;
};
static struct context ctx = {0};
void do_timer(timer_node_t *node)
{
printf("timer expired:%d - thread-id:%d\n", node->expire, node->id);
}
void *thread_worker(void *p)
{
struct thread_param *tp = (struct thread_param *)p;
int id = tp->id;
struct context *ctx = tp->ctx;
while (!ctx->quit)
{
int expire = rand() % 200;
add_timer(expire, do_timer, id);
usleep(expire * (10 - 1) * 1000);
}
printf("thread_worker:%d exit!\n", id);
return NULL;
}
void do_quit(timer_node_t *node)
{
ctx.quit = 1;
}
int main()
{
srand(time(NULL));
ctx.thread = 8;
pthread_t pid[ctx.thread];
init_timer();
add_timer(6000, do_quit, 100);
struct thread_param task_thread_p[ctx.thread];
int i;
for (i = 0; i < ctx.thread; i++)
{
task_thread_p[i].id = i;
task_thread_p[i].ctx = &ctx;
if (pthread_create(&pid[i], NULL, thread_worker, &task_thread_p[i]))
{
fprintf(stderr, "create thread failed\n");
exit(1);
}
}
while (!ctx.quit)
{
expire_timer();
usleep(2500);
}
clear_timer();
for (i = 0; i < ctx.thread; i++)
{
pthread_join(pid[i], NULL);
}
printf("all thread is closed\n");
return 0;
}
到此這篇關(guān)于C++定時(shí)器實(shí)現(xiàn)和時(shí)間輪介紹的文章就介紹,到這了,更多相關(guān)C++定時(shí)器 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++11實(shí)現(xiàn)簡(jiǎn)易定時(shí)器的示例代碼
- C++定時(shí)器Timer在項(xiàng)目中的使用方法
- C++控制臺(tái)用定時(shí)器實(shí)例代碼
- C++?超詳細(xì)分析數(shù)據(jù)結(jié)構(gòu)中的時(shí)間復(fù)雜度
- C++11時(shí)間日期庫chrono的使用
- c++11多種格式時(shí)間轉(zhuǎn)化為字符串的方法實(shí)現(xiàn)
- C++使用chrono庫處理日期和時(shí)間的實(shí)現(xiàn)方法
- 最短時(shí)間學(xué)會(huì)基于C++實(shí)現(xiàn)DFS深度優(yōu)先搜索
相關(guān)文章
詳解散列表算法與其相關(guān)的C語言實(shí)現(xiàn)
這篇文章主要介紹了詳解散列表算法與其相關(guān)的C語言實(shí)現(xiàn),平時(shí)經(jīng)常出現(xiàn)于各大考試競(jìng)賽與程序員面試題目當(dāng)中,需要的朋友可以參考下2015-08-08
C++ 將字符串值賦給CHAR數(shù)組的實(shí)現(xiàn)
這篇文章主要介紹了C++ 將字符串值賦給CHAR數(shù)組的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01
淺談C++的語句語法與強(qiáng)制數(shù)據(jù)類型轉(zhuǎn)換
這篇文章主要介紹了淺談C++的語句語法與強(qiáng)制數(shù)據(jù)類型轉(zhuǎn)換,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
opencv檢測(cè)直線方法之形態(tài)學(xué)方法
這篇文章主要為大家詳細(xì)介紹了opencv檢測(cè)直線方法之形態(tài)學(xué)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Visual?C++?6.0新建一個(gè)C語言文件的圖文教程
本教程適用于C語言初學(xué)者,本文主要介紹了Visual?C++?6.0新建一個(gè)C語言文件的圖文教程,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
C++實(shí)現(xiàn)LeetCode(18.四數(shù)之和)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(18.四數(shù)之和),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07

