在 Linux 下,C 语言中可以通过几种方式使用定时器功能。常见的方法包括使用 timer_create 和 setitimer 系列函数来实现定时器。以下是两种常用方法的详细讲解:


1. 使用 timer_create 和 timer_settime(POSIX 定时器)

POSIX 定时器 API 提供了强大的定时器功能,可以在指定时间间隔后执行回调函数。timer_create 和 timer_settime 允许你创建和管理定时器,提供了更精细的定时控制。

示例代码:

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

void timer_handler(union sigval sv) {
    printf("Timer expired!\n");
}

int main() {
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;

    // 设置信号通知方式
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = timer_handler;
    sev.sigev_value.sival_ptr = &timerid;

    // 创建定时器
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
        perror("timer_create");
        exit(1);
    }

    // 设置定时器超时时间
    its.it_value.tv_sec = 5;  // 初始定时器超时时间(秒)
    its.it_value.tv_nsec = 0; // 初始定时器超时时间(纳秒)
    its.it_interval.tv_sec = 5;  // 定时器周期(秒)
    its.it_interval.tv_nsec = 0; // 定时器周期(纳秒)

    // 启动定时器
    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(1);
    }

    // 程序主循环,等待定时器回调
    while (1) {
        // 可以执行其他任务,定时器回调会在后台处理
        sleep(1);
    }

    return 0;
}

代码说明:

  1. timer_create:创建一个新的定时器。SIGEV_THREAD 指定定时器到期时会创建一个新线程来调用回调函数。
  2. timer_settime:设置定时器的初始超时(it_value)和定时器周期(it_interval)。如果周期为零,定时器将只触发一次。
  3. 回调函数 timer_handler:当定时器到期时,回调函数会被调用,并打印 Timer expired!

2. 使用 setitimer(旧版定时器)

setitimer 也是一个用于设置定时器的函数,但它的控制不如 timer_create 精细,且它依赖于系统信号。setitimer 主要用于实现周期性计时器和一次性定时器。

示例代码:

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

void timer_handler(int sig) {
    printf("Timer expired!\n");
}

int main() {
    struct itimerval timer;

    // 安装定时器信号处理程序
    signal(SIGALRM, timer_handler);

    // 设置定时器:初始超时时间和周期
    timer.it_value.tv_sec = 5;  // 初始超时(秒)
    timer.it_value.tv_usec = 0; // 初始超时(微秒)
    timer.it_interval.tv_sec = 5;  // 定时器周期(秒)
    timer.it_interval.tv_usec = 0; // 定时器周期(微秒)

    // 设置定时器
    if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
        perror("setitimer");
        exit(1);
    }

    // 程序主循环,等待信号
    while (1) {
        sleep(1); // 主循环
    }

    return 0;
}

代码说明:

  1. signal(SIGALRM, timer_handler):注册一个信号处理程序,当定时器超时后会触发 SIGALRM 信号,进而调用 timer_handler 函数。
  2. setitimer:设置定时器的超时和周期。ITIMER_REAL 表示与实际时间相关的定时器,触发时会发送 SIGALRM 信号。
    • it_value:定时器第一次超时的时间。
    • it_interval:定时器周期(如果设置为 0,则为一次性定时器)。

3. 使用 alarm 和 sleep 实现简单定时器

对于不需要高精度的简单定时任务,Linux 也支持使用 alarm 和 sleep 来进行定时。

示例代码:

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

void timer_handler(int sig) {
    printf("Timer expired!\n");
}

int main() {
    signal(SIGALRM, timer_handler);

    // 设置 5 秒后超时
    alarm(5);

    // 程序主循环,等待信号
    while (1) {
        printf("Waiting for timer...\n");
        sleep(1);  // 模拟其他任务
    }

    return 0;
}

代码说明:

  • alarm(5):设置一个简单的定时器,5 秒后触发 SIGALRM 信号,调用 timer_handler 函数。
  • signal(SIGALRM, timer_handler):注册一个信号处理函数,当 SIGALRM 信号触发时,调用 timer_handler

总结

  • timer_create 和 timer_settime:是 POSIX 定时器 API,支持高精度定时,可以设置定时器回调函数,适用于需要精确控制定时的场景。
  • setitimer:较旧的定时器方式,依赖信号处理,适用于简单的定时任务。
  • alarm 和 sleep:非常基础的定时机制,适用于不需要高精度的简单定时需求。

对于更精细的控制和灵活性,建议使用 timer_create 和 timer_settime