设计思路
- 定时器机制:
- 在Linux环境下,选择
timerfd
机制。timerfd
是一种文件描述符形式的定时器,它可以通过epoll
等多路复用机制与其他I/O事件一起处理,非常适合多线程高并发场景。timerfd
定时器基于内核时钟,能提供较高精度的计时。
- 线程同步策略:
- 使用互斥锁(
pthread_mutex_t
)来保护共享资源。对于定时器相关的共享数据,例如定时器的状态、计时参数等,在访问和修改这些数据时,通过加锁和解锁操作来确保同一时间只有一个线程能操作这些数据,避免资源竞争。
- 条件变量(
pthread_cond_t
)用于线程间的同步。当定时器到期触发事件时,通过条件变量通知等待的线程,这样可以避免线程无效的轮询等待。
- 处理定时器中断与主线程任务冲突问题:
- 将定时器事件与主线程任务通过
epoll
多路复用机制进行统一管理。epoll
可以同时监听timerfd
和其他I/O事件,当timerfd
有数据可读时,表示定时器到期,主线程可以在处理epoll
事件时,安全地处理定时器事件,而不会与其他主线程任务产生冲突。
- 对于定时器中断处理逻辑,可以将其设计为一个独立的函数,在主线程处理
epoll
事件时调用该函数,这样可以将定时器相关操作与主线程其他复杂计算任务分离,保证高精度计时不受主线程复杂任务的干扰。
核心代码框架
#include <stdio.h>
#include <stdlib.h>
#include <sys/timerfd.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <time.h>
// 定义定时器相关结构体
typedef struct {
int timerfd;
pthread_mutex_t mutex;
pthread_cond_t cond;
struct itimerspec new_value;
int is_running;
} Timer;
// 初始化定时器
void init_timer(Timer *timer, long long sec, long long nsec) {
pthread_mutex_init(&timer->mutex, NULL);
pthread_cond_init(&timer->cond, NULL);
timer->timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer->timerfd == -1) {
perror("timerfd_create");
exit(EXIT_FAILURE);
}
timer->new_value.it_value.tv_sec = sec;
timer->new_value.it_value.tv_nsec = nsec;
timer->new_value.it_interval.tv_sec = 0;
timer->new_value.it_interval.tv_nsec = 0;
timer->is_running = 0;
}
// 启动定时器
void start_timer(Timer *timer) {
pthread_mutex_lock(&timer->mutex);
if (timerfd_settime(timer->timerfd, 0, &timer->new_value, NULL) == -1) {
perror("timerfd_settime");
pthread_mutex_unlock(&timer->mutex);
return;
}
timer->is_running = 1;
pthread_mutex_unlock(&timer->mutex);
}
// 停止定时器
void stop_timer(Timer *timer) {
pthread_mutex_lock(&timer->mutex);
struct itimerspec zero = {{0, 0}, {0, 0}};
if (timerfd_settime(timer->timerfd, 0, &zero, NULL) == -1) {
perror("timerfd_settime");
pthread_mutex_unlock(&timer->mutex);
return;
}
timer->is_running = 0;
pthread_mutex_unlock(&timer->mutex);
}
// 定时器事件处理函数
void handle_timer_event(Timer *timer) {
uint64_t exp;
ssize_t s = read(timer->timerfd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
perror("read");
}
// 这里可以添加定时器到期后的具体处理逻辑
printf("Timer expired\n");
}
// 主线程函数
void* main_thread(void* arg) {
Timer *timer = (Timer*)arg;
int epollfd = epoll_create1(0);
if (epollfd == -1) {
perror("epoll_create1");
pthread_exit(NULL);
}
struct epoll_event event;
event.data.ptr = timer;
event.events = EPOLLIN;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, timer->timerfd, &event) == -1) {
perror("epoll_ctl: timerfd");
close(epollfd);
pthread_exit(NULL);
}
struct epoll_event events[1];
while (1) {
int n = epoll_wait(epollfd, events, 1, -1);
if (n == -1) {
perror("epoll_wait");
break;
}
for (int i = 0; i < n; ++i) {
Timer *t = (Timer*)events[i].data.ptr;
handle_timer_event(t);
}
// 这里可以添加主线程其他复杂计算任务
}
close(epollfd);
pthread_exit(NULL);
}
int main() {
Timer timer;
init_timer(&timer, 1, 0); // 1秒定时器
pthread_t tid;
if (pthread_create(&tid, NULL, main_thread, &timer) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
start_timer(&timer);
pthread_join(tid, NULL);
stop_timer(&timer);
close(timer.timerfd);
pthread_mutex_destroy(&timer.mutex);
pthread_cond_destroy(&timer.cond);
return 0;
}