MST

星途 面试题库

面试题:C语言在Linux复杂场景下的高精度定时器设计

在一个多线程、高并发的Linux C语言应用程序中,需要设计一个高精度定时器,该定时器既要满足在复杂计算任务执行过程中仍能保持高精度计时,又要避免与其他线程产生资源竞争。请详细描述你的设计思路,包括所选用的定时器机制、线程同步策略以及如何处理可能出现的定时器中断与主线程任务冲突问题,并给出核心代码框架。
13.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定时器机制
    • 在Linux环境下,选择timerfd机制。timerfd是一种文件描述符形式的定时器,它可以通过epoll等多路复用机制与其他I/O事件一起处理,非常适合多线程高并发场景。timerfd定时器基于内核时钟,能提供较高精度的计时。
  2. 线程同步策略
    • 使用互斥锁(pthread_mutex_t)来保护共享资源。对于定时器相关的共享数据,例如定时器的状态、计时参数等,在访问和修改这些数据时,通过加锁和解锁操作来确保同一时间只有一个线程能操作这些数据,避免资源竞争。
    • 条件变量(pthread_cond_t)用于线程间的同步。当定时器到期触发事件时,通过条件变量通知等待的线程,这样可以避免线程无效的轮询等待。
  3. 处理定时器中断与主线程任务冲突问题
    • 将定时器事件与主线程任务通过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;
}