Linux 环境编程 用户层定时器使用二 timer_create的使用

用户层定时器有两种,一种是timerfd,另一种是timer_create,前者比较新,使用比较方便。

Linux环境编程 用户层定时器使用一 timerfd的使用

https://blog.csdn.net/fuyuande/article/details/80658695

这里记录一下timer_create的用法。

先介绍一下相关接口,再结合一个简单的demo介绍一下使用

头文件:
       #include <signal.h>
       #include <time.h>

/* 
 * 创建定时器
 * 创建POSIX定时器,不会被传递给子进程。编译时候增加编译选项 -lrt
 * 定时器ID存储在timerid中,定时器ID在当前进程中是唯一的,除非定时器
 * 被删除。初始化的时候定时器未启动。
 * clockid定义了定时器计时的方法,有如下几个值:
 * CLOCK_REALTIME : 可设置的系统范围的实时时钟
 * CLOCK_MONOTONIC : 单调递增的时钟,系统启动后不会被改变
 * CLOCK_PROCESS_CPUTIME_ID : 用于测量当前进程(包括所有线程)CPU占用时间,包含用户调用和系统调用,
 * CLOCK_THREAD_CPUTIME_ID : 用于测量当前线程CPU占用时间,包含用户调用和系统调用
 * 参数sevp指出该如何通知调用者定时器超时信息,根据sevp.sigev_notify字段,该字段有如下值
 * SIGEV_NONE : 定时器超时后不使用异步通知,可能的情况是使用timer_gettime来监控定时器
 * SIGEV_SIGNAL : 一旦超时,产生一个信号,任何时候,至多只有一个信号会发送到队列里面,可以使用timer_getoverrun来获取超时次数
 * SIGEV_THREAD : 新建一个线程去处理,该线程执行sigev_notif_function为入口函数
 * SIGEV_THREAD_ID : linux独有,发出一个信号,和SIG_NAL类似,只不过该信号发送到指定的线程。
 * NULL : 如果sevp被设置为NULL,相当于SIGEV_SIGNAL,信号是SIGALRM
 * 返回值,成功返回0,失败返回-1并将错误码设置到errno里 
 */

int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);

使用到的时间参数数据结构体有下面两该个
struct timespec {
    time_t tv_sec;                /* Seconds */
    long   tv_nsec;               /* Nanoseconds */
};
struct itimerspec {
    struct timespec it_interval;  /* Timer interval */
    struct timespec it_value;     /* Initial expiration */
};

/*
 * 启动/关闭定时器
 * itimerspec将时间分为秒和纳秒的组合
 * 如果参数new_value->it_value不为0,则启动定时器。如果定时器已经启动则覆盖之前的定时器设置
 * 如果参数new_value->it_value为0则关闭定时器。
 * 参数new_value->it_interval用于定时器重启的间隔,即当定时器超时后下一次超时的间隔。
 * 参数flags为0的话默认是相对时间,也可以使用TIMER_ABSTIME绝对时间
 * 成功返回0,失败返回-1,并设置errno
 */
int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value);

/*
 * 返回到下一次超时的时间间隔,如果返回0说明已经超时
 */
int timer_gettime(timer_t timerid, struct itimerspec *curr_value);

/*
 * 删除定时器
 * 成功返回0,失败返回-1并设置errno
 */
 int timer_delete(timer_t timerid); 

下面是一个简单例子,创建一个定时器,超时时间1s, 超时后发出信号,超时5次后程序退出

/*
 *  Description : Linux用户层定时器使用<二>
         定义一个每个1s触发的定时器,定时器触发后发出信号并打印,
         超过5次后程序自动退出。
         
 *  Author      : mason
 *  Date        : 201808
 */

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

#define EXPIRE_MAX 5
static int expire_cnt;

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

/* 定时器回调函数 */
void timer_handler()  
{  
    
    if (expire_cnt < EXPIRE_MAX)
    {
        expire_cnt++;
    }
    printf("timer expire\r\n");
    return;
} 

int main(int argc, char *argv[])
{
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;

    /* 注册信号回调函数 */
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGUSR1;
    sev.sigev_value.sival_ptr = &timerid;
    signal(SIGUSR1, timer_handler);

    /* 创建定时器 */
    if (timer_create(CLOCK_MONOTONIC, &sev, &timerid) == -1)
    {
        errExit("timer_create");
    }

    /* 设置定时器时间参数超时1s */
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = its.it_value.tv_sec;
    its.it_interval.tv_nsec = its.it_value.tv_nsec;

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

    /* 超时5次后退出 */
    while (expire_cnt != 5) 
    {
        sleep(1);
    }

    /* 删除定时器 */
    timer_delete(timerid);
    
    exit(EXIT_SUCCESS);
}

timer_create和timerfd相比的话,接口复杂,需要使用到信号机制,实际使用的话建议使用timerfd。

参考资料:

1. man timer_create: https://linux.die.net/man/2/timer_create

2. POSIX定时器:timer_settime()

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux应用编程中的定时器是一种机制,用于在某个时间间隔后执行某个任务。在Linux系统中,有两种类型的定时器:内核定时器用户空间定时器。 内核定时器是由内核维护的定时器,用于在系统空闲时执行一些任务,比如定期更新系统状态、清理内存等。内核定时器可以使用系统调用setitimertimer_create来创建和管理。 用户空间定时器是由应用程序维护的定时器,用于在应用程序中执行某些任务,比如定期更新UI界面、发送网络请求等。用户空间定时器可以使用POSIX定时器API来创建和管理。 POSIX定时器API包括以下函数: 1. timer_create:创建一个定时器。 2. timer_settime:设置定时器的时间和周期。 3. timer_gettime:获取定时器的当前时间。 4. timer_delete:删除一个定时器使用定时器时,需要先创建定时器,然后设置定时器的时间和周期,最后在定时器到期时执行相应的任务。例如,下面是一个使用POSIX定时器API创建并设置定时器的示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> timer_t timerid; void timer_handler(int sig) { printf("Timer expired!\n"); } int main() { struct sigevent sev; struct itimerspec its; struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = timer_handler; sigemptyset(&sa.sa_mask); sigaction(SIGRTMIN, &sa, NULL); sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCK_REALTIME, &sev, &timerid); 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); while(1); return 0; } ``` 在上面的示例代码中,首先创建了一个定时器timerid,然后设置了定时器的时间和周期为1秒。当定时器到期时,会触发SIGRTMIN信号,执行timer_handler函数。最后,程序进入一个死循环,等待定时器到期。 总之,定时器Linux应用编程中非常重要的一个机制,可以帮助应用程序在必要的时候执行一些任务,提高程序的效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值