Linux基础 -- Linux C 用户态定时器的使用

Linux 中用户态C++定时器的使用

在Linux中,timer_create函数可以使用不同的时钟选项来创建定时器。主要的时钟选项有以下几种:

  1. CLOCK_REALTIME
  2. CLOCK_MONOTONIC
  3. CLOCK_PROCESS_CPUTIME_ID
  4. CLOCK_THREAD_CPUTIME_ID
  5. CLOCK_BOOTTIME
  6. CLOCK_REALTIME_ALARM
  7. CLOCK_BOOTTIME_ALARM

1. CLOCK_REALTIME

  • 用途:基于系统实时时钟。这个时钟可以被系统时间的改变所影响(例如通过settimeofday或NTP同步)。
  • 用法:通常用于需要知道真实时间的应用。
timer_create(CLOCK_REALTIME, &sev, &timerId);

2. CLOCK_MONOTONIC

  • 用途:单调递增时钟。这个时钟不会受到系统时间改变的影响,适合测量时间间隔。
  • 用法:适用于需要稳定时间间隔的应用,如测量程序运行时间。
timer_create(CLOCK_MONOTONIC, &sev, &timerId);

3. CLOCK_PROCESS_CPUTIME_ID

  • 用途:用于测量调用进程的CPU时间。
  • 用法:适合用于需要精确测量某个进程CPU使用时间的应用。
timer_create(CLOCK_PROCESS_CPUTIME_ID, &sev, &timerId);

4. CLOCK_THREAD_CPUTIME_ID

  • 用途:用于测量调用线程的CPU时间。
  • 用法:适合用于需要精确测量某个线程CPU使用时间的应用。
timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &timerId);

5. CLOCK_BOOTTIME

  • 用途:类似于CLOCK_MONOTONIC,但包括系统睡眠时间。
  • 用法:适合需要知道系统运行总时间(包括睡眠时间)的应用。
timer_create(CLOCK_BOOTTIME, &sev, &timerId);

6. CLOCK_REALTIME_ALARM

  • 用途:类似于CLOCK_REALTIME,但用于唤醒系统或发出警报。
  • 用法:适合用于需要在特定时间唤醒系统的应用。
timer_create(CLOCK_REALTIME_ALARM, &sev, &timerId);

7. CLOCK_BOOTTIME_ALARM

  • 用途:类似于CLOCK_BOOTTIME,但用于唤醒系统或发出警报。
  • 用法:适合用于需要在特定时间唤醒系统且包括睡眠时间的应用。
timer_create(CLOCK_BOOTTIME_ALARM, &sev, &timerId);

示例代码

以下是使用CLOCK_MONOTONIC时钟选项的示例代码:

#include <iostream>
#include <signal.h>
#include <time.h>
#include <unistd.h>

// 定时器触发的处理函数
void timerHandler(int sig, siginfo_t *si, void *uc) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);

    std::cout << "Timer triggered! Current time: " << ts.tv_sec << " seconds and " << ts.tv_nsec << " nanoseconds" << std::endl;
}

int main() {
    struct sigaction sa;
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timerHandler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGRTMIN, &sa, NULL);

    timer_t timerId;
    struct sigevent sev;
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &timerId;
    timer_create(CLOCK_MONOTONIC, &sev, &timerId);

    struct itimerspec its;
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;
    timer_settime(timerId, 0, &its, NULL);

    sleep(5); // 主线程休眠5秒

    timer_delete(timerId); // 停止定时器
    return 0;
}

定时器不销毁但cancel的方法

下面详细介绍如何创建定时器,并通过将 itimerspec 结构的所有字段设置为零来取消定时器。
注意
如果老设置的struct itimerspecit_interval被设置非零0后会设置cancel失败;

timer_settime
启动或停止一个定时器。

#include <time.h>

int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);

itimerspec
描述定时器的启动时间和间隔时间。

struct itimerspec {
    struct timespec it_interval; /* Interval for periodic timer */
    struct timespec it_value;    /* Initial expiration */
};

示例代码
下面是一个完整的示例代码,展示了如何创建一个定时器并取消它。

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

void timer_handler(int sig, siginfo_t *si, void *uc) {
    printf("Timer expired!\n");
}

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

    // 设置定时器的处理函数
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigaction(SIGRTMIN, &sa, NULL);

    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &timerid;
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }

    // 设置定时器初始时间和间隔时间
    its.it_value.tv_sec = 2;  // 2秒后触发定时器
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;  // 不重复
    its.it_interval.tv_nsec = 0;
    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }

    // 等待3秒,让定时器触发
    sleep(3);

    // 取消定时器
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        perror("timer_settime (cancel)");
        exit(EXIT_FAILURE);
    }

    // 等待2秒,验证定时器已取消
    sleep(2);
    printf("Timer cancelled.\n");

    // 删除定时器
    if (timer_delete(timerid) == -1) {
        perror("timer_delete");
        exit(EXIT_FAILURE);
    }

    return 0;
}

代码解析

  1. 设置信号处理函数:使用 sigaction 设置定时器到期时的处理函数 timer_handler
  2. 创建定时器:使用 timer_create 创建一个新的定时器。
  3. 设置定时器时间:使用 timer_settime 设置定时器的初始到期时间和间隔时间。
  4. 等待定时器触发:通过 sleep 等待定时器触发。
  5. 取消定时器:再次使用 timer_settime,将 itimerspec 结构的所有字段设置为零,取消定时器。
  6. 验证定时器已取消:通过 sleep 验证定时器已取消,不会再触发。
  7. 删除定时器:使用 timer_delete 删除定时器。

回调函数关联上下文的用法

可以通过设置 sigevent 结构体中的 sigev_value 字段,将上下文信息传递给 timer_handler 回调函数。sigev_value 字段可以是一个 union,它可以存储指向任意数据类型的指针。这样,当定时器到期时,信号处理函数可以访问这些上下文信息。

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

typedef struct {
    timer_t timerid;
    int some_data;
} timer_context_t;

void timer_handler(int sig, siginfo_t *si, void *uc) {
    timer_context_t *ctx = (timer_context_t *)si->si_value.sival_ptr;
    printf("Timer expired! some_data = %d\n", ctx->some_data);
}

int main() {
    timer_context_t ctx;
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;

    // 设置定时器的处理函数
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigaction(SIGRTMIN, &sa, NULL);

    // 创建定时器
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &ctx;
    if (timer_create(CLOCK_REALTIME, &sev, &ctx.timerid) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }

    // 设置上下文数据
    ctx.some_data = 42;

    // 设置定时器初始时间和间隔时间
    its.it_value.tv_sec = 2;  // 2秒后触发定时器
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;  // 不重复
    its.it_interval.tv_nsec = 0;
    if (timer_settime(ctx.timerid, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }

    // 等待3秒,让定时器触发
    sleep(3);

    // 取消定时器
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    if (timer_settime(ctx.timerid, 0, &its, NULL) == -1) {
        perror("timer_settime (cancel)");
        exit(EXIT_FAILURE);
    }

    // 等待2秒,验证定时器已取消
    sleep(2);
    printf("Timer cancelled.\n");

    // 删除定时器
    if (timer_delete(ctx.timerid) == -1) {
        perror("timer_delete");
        exit(EXIT_FAILURE);
    }

    return 0;
}

代码解析

  1. 设置信号处理函数:使用 sigaction 设置定时器到期时的处理函数 timer_handler
  2. 创建定时器:使用 timer_create 创建一个新的定时器,并将上下文数据 ctx 通过 sigev_value.sival_ptr 传递。
  3. 设置上下文数据:在上下文结构体中存储需要在处理函数中访问的数据。
  4. 设置定时器时间:使用 timer_settime 设置定时器的初始到期时间和间隔时间。
  5. 等待定时器触发:通过 sleep 等待定时器触发,并在触发时通过上下文数据进行处理。
  6. 取消定时器:再次使用 timer_settime,将 itimerspec 结构的所有字段设置为零,取消定时器。
  7. 验证定时器已取消:通过 sleep 验证定时器已取消,不会再触发。
  8. 删除定时器:使用 timer_delete 删除定时器。
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个Linux用户定时器的简单例程: ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <unistd.h> #define TIMER_SIG SIGRTMIN void timer_handler(int sig, siginfo_t *si, void *uc) { printf("Timer expired.\n"); } int main(int argc, char *argv[]) { timer_t timerid; struct sigevent sev; struct itimerspec its; struct sigaction sa; // 设置定时器信号处理函数 sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = timer_handler; sigemptyset(&sa.sa_mask); if (sigaction(TIMER_SIG, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = TIMER_SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { perror("timer_create"); exit(EXIT_FAILURE); } // 设置定时器 its.it_value.tv_sec = 5; // 初始定时器时间为5秒 its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; // 定时器到期后每1秒重新启动一次 its.it_interval.tv_nsec = 0; if (timer_settime(timerid, 0, &its, NULL) == -1) { perror("timer_settime"); exit(EXIT_FAILURE); } // 循环等待定时器信号 while (1) { sleep(1); } return 0; } ``` 该程序使用 `timer_create()` 创建一个定时器,并使用 `timer_settime()` 设置定时器的初始值和周期值。在定时器到期时,会触发一个 `SIGRTMIN` 信号,该信号将被注册的信号处理函数 `timer_handler()` 捕获并执行。在该例程中,我们简单地打印了一条消息来表示定时器已经到期。 要编译上述程序,请使用以下命令: ``` gcc -o timer timer.c ``` 运行程序,它将等待5秒钟,然后输出一条消息,之后每隔1秒钟再输出一条消息。你可以使用 `Ctrl+C` 组合键来中断程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值