Linux定时器

1. Linux定时器概述

Linux提供了多种定时器机制,用于在特定时间点或周期性地执行任务。

1.1 定时器类型

  • 间隔定时器:setitimer,传统的UNIX定时器
  • POSIX定时器:timer_create,更灵活的定时器
  • 内核定时器:用于内核模块开发
  • 高精度定时器:hrtimer,纳秒级精度

2. 间隔定时器 (setitimer)

2.1 基本用法

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>

// 定时器信号处理函数
void timer_handler(int sig) {
    static int count = 0;
    printf("Timer expired %d times\n", ++count);
}

int main() {
    struct itimerval timer;
    struct sigaction sa;
    
    printf("Setting up interval timer...\n");
    printf("Process PID: %d\n", getpid());
    
    // 设置信号处理
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = timer_handler;
    sigaction(SIGALRM, &sa, NULL);
    
    // 配置定时器:首次1秒后触发,之后每2秒触发
    timer.it_value.tv_sec = 1;      // 第一次到期时间
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 2;   // 间隔时间
    timer.it_interval.tv_usec = 0;
    
    // 启动定时器
    if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
        perror("setitimer");
        exit(EXIT_FAILURE);
    }
    
    printf("Timer started. First expiration in 1 second, then every 2 seconds.\n");
    
    // 主循环
    while (1) {
        pause();  // 等待信号
    }
    
    return 0;
}

2.2 三种定时器类型

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>

void real_timer_handler(int sig) {
    printf("REAL timer: wall clock time elapsed\n");
}

void virtual_timer_handler(int sig) {
    printf("VIRTUAL timer: process CPU time elapsed\n");
}

void prof_timer_handler(int sig) {
    printf("PROF timer: process CPU time (system + user) elapsed\n");
}

int main() {
    struct itimerval timer;
    struct sigaction sa;
    
    // 设置信号处理函数
    memset(&sa, 0, sizeof(sa));
    
    // 实时定时器(实际时间)
    sa.sa_handler = real_timer_handler;
    sigaction(SIGALRM, &sa, NULL);
    
    // 虚拟定时器(用户态CPU时间)
    sa.sa_handler = virtual_timer_handler;
    sigaction(SIGVTALRM, &sa, NULL);
    
    // 统计分析定时器(总CPU时间)
    sa.sa_handler = prof_timer_handler;
    sigaction(SIGPROF, &sa, NULL);
    
    // 设置实时定时器:每3秒
    timer.it_value.tv_sec = 3;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 3;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &timer, NULL);
    
    // 设置虚拟定时器:每1秒用户CPU时间
    timer.it_value.tv_sec = 1;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_VIRTUAL, &timer, NULL);
    
    // 设置统计分析定时器:每2秒总CPU时间
    timer.it_value.tv_sec = 2;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 2;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_PROF, &timer, NULL);
    
    printf("All timers started. Doing some work...\n");
    
    // 模拟一些CPU工作
    int i = 0;
    while (1) {
        // 用户态工作
        for (long j = 0; j < 1000000; j++) {
            i += j % 100;
        }
        
        // 系统调用(进入内核态)
        usleep(100000);  // 睡眠100ms
        
        if (i > 1000000000) break; // 防止溢出
    }
    
    return 0;
}

3. POSIX定时器

3.1 基本用法

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>

timer_t timer_id;

// 定时器通知处理函数
void timer_callback(union sigval val) {
    static int count = 0;
    int *user_data = (int *)val.sival_ptr;
    
    printf("POSIX Timer callback: count=%d, user_data=%d\n", 
           ++count, *user_data);
    
    // 修改用户数据
    (*user_data)++;
}

int main() {
    struct sigevent sev;
    struct itimerspec its;
    int user_data = 100;
    
    printf("Creating POSIX timer...\n");
    
    // 设置定时器事件
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;  // 创建新线程执行回调
    sev.sigev_value.sival_ptr = &user_data;  // 传递用户数据
    sev.sigev_notify_function = timer_callback;
    sev.sigev_notify_attributes = NULL;  // 使用默认线程属性
    
    // 创建定时器
    if (timer_create(CLOCK_REALTIME, &sev, &timer_id) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }
    
    // 设置定时器:首次1秒后,之后每2秒
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 2;
    its.it_interval.tv_nsec = 0;
    
    // 启动定时器
    if (timer_settime(timer_id, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
    
    printf("POSIX timer started. Running for 10 seconds...\n");
    
    // 运行一段时间
    sleep(10);
    
    // 删除定时器
    timer_delete(timer_id);
    printf("Timer deleted. Exiting.\n");
    
    return 0;
}

3.2 多种通知方式

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>

timer_t timer1, timer2, timer3;

// 信号处理函数
void signal_handler(int sig, siginfo_t *info, void *context) {
    printf("Signal %d received from timer, user_data=%d\n", 
           sig, *(int *)info->si_value.sival_ptr);
}

// 线程回调函数
void thread_callback(union sigval val) {
    printf("Thread callback: user_data=%d\n", *(int *)val.sival_ptr);
}

int main() {
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;
    int user_data1 = 100, user_data2 = 200, user_data3 = 300;
    
    printf("Testing different POSIX timer notifications...\n");
    
    // 方式1:信号通知
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = signal_handler;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGUSR1, &sa, NULL);
    
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGUSR1;
    sev.sigev_value.sival_ptr = &user_data1;
    timer_create(CLOCK_REALTIME, &sev, &timer1);
    
    // 方式2:线程回调
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_value.sival_ptr = &user_data2;
    sev.sigev_notify_function = thread_callback;
    timer_create(CLOCK_REALTIME, &sev, &timer2);
    
    // 方式3:不通知(用于统计)
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_NONE;
    timer_create(CLOCK_REALTIME, &sev, &timer3);
    
    // 启动定时器1:每3秒,信号通知
    its.it_value.tv_sec = 3;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 3;
    its.it_interval.tv_nsec = 0;
    timer_settime(timer1, 0, &its, NULL);
    
    // 启动定时器2:每5秒,线程回调
    its.it_value.tv_sec = 5;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 5;
    its.it_interval.tv_nsec = 0;
    timer_settime(timer2, 0, &its, NULL);
    
    printf("Timers started. Running for 20 seconds...\n");
    sleep(20);
    
    // 清理
    timer_delete(timer1);
    timer_delete(timer2);
    timer_delete(timer3);
    
    printf("All timers deleted.\n");
    return 0;
}

4. 高精度定时器 (hrtimer)

4.1 用户空间高精度定时器

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>

timer_t timer_id;

void high_res_handler(union sigval val) {
    struct timespec ts;
    static int count = 0;
    
    // 获取高精度时间
    clock_gettime(CLOCK_MONOTONIC, &ts);
    
    printf("High-res timer: count=%d, time=%.6f seconds\n",
           ++count, ts.tv_sec + ts.tv_nsec / 1e9);
}

int main() {
    struct sigevent sev;
    struct itimerspec its;
    
    printf("High-resolution timer test (nanosecond precision)\n");
    
    // 创建高精度定时器
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = high_res_handler;
    
    if (timer_create(CLOCK_MONOTONIC, &sev, &timer_id) == -1) {
        perror("timer_create CLOCK_MONOTONIC");
        exit(EXIT_FAILURE);
    }
    
    // 设置高精度定时:每100毫秒
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 100000000;  // 100ms
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 100000000;  // 100ms
    
    if (timer_settime(timer_id, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
    
    printf("High-resolution timer started (100ms intervals). Running for 5 seconds...\n");
    sleep(5);
    
    // 获取定时器剩余时间
    struct itimerspec curr_its;
    timer_gettime(timer_id, &curr_its);
    printf("Remaining time: %ld.%09ld seconds\n", 
           curr_its.it_value.tv_sec, curr_its.it_value.tv_nsec);
    
    timer_delete(timer_id);
    printf("High-resolution timer deleted.\n");
    
    return 0;
}

5. 定时器在应用中的使用

5.1 超时处理示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>

static volatile sig_atomic_t timeout_occurred = 0;

void timeout_handler(int sig) {
    timeout_occurred = 1;
    printf("Timeout! Operation took too long.\n");
}

// 带超时的读取操作
ssize_t read_with_timeout(int fd, void *buf, size_t count, int timeout_sec) {
    struct itimerval timer, old_timer;
    struct sigaction sa, old_sa;
    ssize_t n;
    
    // 设置超时处理
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = timeout_handler;
    sigaction(SIGALRM, &sa, &old_sa);
    
    // 设置定时器
    timer.it_value.tv_sec = timeout_sec;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 0;
    
    timeout_occurred = 0;
    setitimer(ITIMER_REAL, &timer, &old_timer);
    
    // 执行读取操作
    n = read(fd, buf, count);
    
    // 恢复原来的定时器和信号处理
    setitimer(ITIMER_REAL, &old_timer, NULL);
    sigaction(SIGALRM, &old_sa, NULL);
    
    if (timeout_occurred) {
        errno = ETIMEDOUT;
        return -1;
    }
    
    return n;
}

int main() {
    char buf[256];
    
    printf("Read with timeout example. You have 5 seconds to type something:\n");
    
    ssize_t n = read_with_timeout(STDIN_FILENO, buf, sizeof(buf) - 1, 5);
    
    if (n == -1) {
        if (errno == ETIMEDOUT) {
            printf("Read operation timed out.\n");
        } else {
            perror("read");
        }
    } else {
        buf[n] = '\0';
        printf("Successfully read: %s", buf);
    }
    
    return 0;
}

5.2 周期性任务调度

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>

typedef struct {
    int task_id;
    int execution_count;
    long total_execution_time;
} task_context_t;

timer_t timer_id;
task_context_t task_ctx = {1, 0, 0};

void periodic_task(union sigval val) {
    task_context_t *ctx = (task_context_t *)val.sival_ptr;
    struct timespec start, end;
    
    // 记录开始时间
    clock_gettime(CLOCK_MONOTONIC, &start);
    
    // 模拟任务执行
    printf("Task %d executing... (count=%d)\n", 
           ctx->task_id, ++ctx->execution_count);
    
    // 模拟一些工作
    for (volatile long i = 0; i < 1000000; i++) {
        // 空循环模拟工作
    }
    
    // 记录结束时间并计算执行时间
    clock_gettime(CLOCK_MONOTONIC, &end);
    long execution_time = (end.tv_sec - start.tv_sec) * 1000000 + 
                         (end.tv_nsec - start.tv_nsec) / 1000;
    
    ctx->total_execution_time += execution_time;
    
    printf("Task %d completed in %ld microseconds\n", 
           ctx->task_id, execution_time);
}

int main() {
    struct sigevent sev;
    struct itimerspec its;
    
    printf("Periodic task scheduler started.\n");
    
    // 创建定时器
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_value.sival_ptr = &task_ctx;
    sev.sigev_notify_function = periodic_task;
    
    if (timer_create(CLOCK_MONOTONIC, &sev, &timer_id) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }
    
    // 设置周期性执行:每1秒
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;
    
    if (timer_settime(timer_id, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
    
    printf("Periodic task scheduled every 1 second. Running for 10 seconds...\n");
    sleep(10);
    
    // 停止定时器
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    timer_settime(timer_id, 0, &its, NULL);
    
    printf("\nTask statistics:\n");
    printf("  Executions: %d\n", task_ctx.execution_count);
    printf("  Total execution time: %ld microseconds\n", task_ctx.total_execution_time);
    printf("  Average execution time: %.2f microseconds\n", 
           (float)task_ctx.total_execution_time / task_ctx.execution_count);
    
    timer_delete(timer_id);
    printf("Scheduler stopped.\n");
    
    return 0;
}

6. 内核定时器示例

6.1 简单内核模块定时器

/*
 * 内核定时器示例模块
 * 需要root权限加载:insmod timer_module.ko
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>

static struct timer_list my_timer;
static int count = 0;

void timer_callback(struct timer_list *t) {
    printk(KERN_INFO "Kernel timer callback: count = %d\n", ++count);
    
    // 重新设置定时器(1秒后)
    mod_timer(&my_timer, jiffies + HZ);
}

static int __init timer_init(void) {
    printk(KERN_INFO "Initializing kernel timer module\n");
    
    // 初始化定时器
    timer_setup(&my_timer, timer_callback, 0);
    
    // 启动定时器(1秒后到期)
    mod_timer(&my_timer, jiffies + HZ);
    
    return 0;
}

static void __exit timer_exit(void) {
    // 删除定时器
    del_timer(&my_timer);
    printk(KERN_INFO "Kernel timer module unloaded, total callbacks: %d\n", count);
}

module_init(timer_init);
module_exit(timer_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple kernel timer example");

7. 最佳实践和注意事项

7.1 定时器使用准则

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>

// 1. 避免在信号处理函数中调用不可重入函数
void safe_timer_handler(int sig) {
    // 安全:只设置标志或使用原子操作
    static volatile sig_atomic_t flag = 0;
    flag = 1;
    
    // 不安全:printf, malloc等不可重入函数
    // printf("Timer!\n"); // 危险!
}

// 2. 处理定时器竞争条件
void race_condition_example() {
    printf("Timer race condition considerations:\n");
    printf("1. 设置定时器和检查标志需要同步\n");
    printf("2. 考虑使用原子操作或锁\n");
    printf("3. 在信号处理中做最少的工作\n");
}

// 3. 资源清理
void cleanup_timer(timer_t timer_id) {
    // 停止定时器
    struct itimerspec its;
    memset(&its, 0, sizeof(its));
    timer_settime(timer_id, 0, &its, NULL);
    
    // 删除定时器
    timer_delete(timer_id);
    printf("Timer cleaned up successfully.\n");
}

// 4. 错误处理
int robust_timer_create(timer_t *timer_id, void (*handler)(union sigval)) {
    struct sigevent sev;
    
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = handler;
    
    if (timer_create(CLOCK_REALTIME, &sev, timer_id) == -1) {
        perror("Failed to create timer");
        return -1;
    }
    
    return 0;
}

int main() {
    printf("Timer best practices:\n");
    printf("1. 选择适合的定时器类型\n");
    printf("2. 考虑精度和性能需求\n");
    printf("3. 正确处理信号和线程安全\n");
    printf("4. 总是清理定时器资源\n");
    printf("5. 处理可能的错误情况\n");
    
    return 0;
}

8. 性能比较和选择指南

定时器类型 精度 性能 适用场景
setitimer 微秒 中等 简单间隔定时
POSIX定时器 纳秒 复杂定时需求
高精度定时器 纳秒 很高 实时应用
内核定时器 毫秒 很高 内核开发

Linux定时器提供了灵活的定时功能,根据应用需求选择合适的定时器类型非常重要。对于用户空间应用,推荐使用POSIX定时器;对于高性能需求,考虑高精度定时器;对于内核开发,使用内核定时器API。