POSIX Timer

一、特点:

1、使用 POSIX Timer,一个进程可以创建任意多个 Timer。
2、setitmer 计时器时间到达时,可以有多种通知方式,比如信号,或者启动线程。
3、POSIX Timer 则可以使用实时信号。
4、POSIX Timer 是针对有实时要求的应用所设计的,接口支持 ns 级别的时钟精度。

二、相关API

(1)创建timer

int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)

参数:

clock_id:说明定时器是基于哪个时钟的,一般使用CLOCK_REALTIME即可。取值如下:

CLOCK_REALTIME :Systemwide realtime clock. //时间是系统保存的时间,即可以由 date 命令显示的时间,该时间可以重新设置。
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set.
CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer.  //CLOCK_PROCESS_CPUTIME_ID 的含义与 setitimer 的 ITIMER_VIRTUAL 类似。
CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.// CLOCK_THREAD_CPUTIME_ID 以线程为计时实体,当前进程中的某个线程真正地运行了一定时间才触发 Timer。
CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME. 
CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.

*timerid 装载的是被创建的定时器的 ID句柄,类型是int。就像open函数返回的文件描述符一样。

*evp 指定了定时器到期要产生的异步通知,结构体定义如下:

union sigval {          /* Data passed with notification */
    int     sival_int;         /* Integer value */
    void   *sival_ptr;         /* Pointer value */
};

typedef struct sigevent {
    sigval_t sigev_value;
    int sigev_signo;
    int sigev_notify;
    union {
        int _pad[SIGEV_PAD_SIZE];
         int _tid;

        struct {
            void (*_function)(sigval_t);
            void *_attribute;    /* really pthread_attr_t */
        } _sigev_thread;
    } _sigev_un;
} sigevent_t;

struct sigevent 结构中的成员 evp->sigev_notify说明了定时器到期时应该采取的行动,可以设定:

(a)SIGEV_NONE。不需要异步通知,程序自己调用timer_gettime来轮询timer的当前状态

(b)SIGEV_SIGNAL。使用sinal这样的异步通知方式。发送的信号由sigev_signo定义。如果发送的是realtime signal,该信号的附加数据由sigev_value定义。

(c)SIGEV_THREAD。创建一个线程执行timer超期callback函数,_attribute定义了该线程的属性。

(d)SIGEV_THREAD_ID。行为和SIGEV_SIGNAL类似,不过发送的信号被送达进程内的一个指定的thread,这个thread由_tid标识。

如果evp为 NULL,那么定时器到期会产生默认的信号,对 CLOCK_REALTIMER来说,默认信号就是SIGALRM。如果要产生除默认信号之外的其它信号,程序必须将 evp->sigev_signo设置为期望的信号码。

(2)设定timer

#include <time.h>

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

struct itimespec{
    struct timespec it_interval; // 后续按照该时间间隔
    struct timespec it_value;   // 最初开始时间间隔
}; 

如果new_value.it_value是一个非0值,那么调用timer_settime可以启动该timer。如果new_value.it_value是一个0值,那么调用timer_settime可以stop该timer。

如果flags的值为TIMER_ABSTIME,则value所指定的时间值会被解读成绝对值(此值的默认的解读方式为相对于当前的时间)。这个经修改的行为可避免取得当前时间、计算“该时间”与“所期望的未来时间”的相对差额以及启动定时器期间造成竞争条件。 如果ovalue的值不是NULL,则之前的定时器到期时间会被存入其所提供的itimerspec。如果定时器之前处在未启动状态,则此结构的成员全都会被设定成0。

(3)删除timer

#include <time.h>

int timer_delete(timer_t timerid);

有创建就有删除,timer_delete用来删除指定的timer,释放资源。

三、使用示例

(1)线程通知

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


void  handle(union sigval v){
    time_t t;
    char p[32];
    time(&t);
    strftime(p, sizeof(p), "%T", localtime(&t));
    printf("%s thread %lu, val = %d, signal captured.\n", p, pthread_self(), v.sival_int);
    return;
}

int main(int argc, char *argv[]){

    struct sigevent evp;
    struct itimerspec ts;
    timer_t timer;
    int ret;
    memset   (&evp, 0, sizeof(evp));
    evp.sigev_value.sival_ptr = &timer;
    evp.sigev_notify = SIGEV_THREAD;
    evp.sigev_notify_function = handle;
    evp.sigev_value.sival_int = 3;   //作为handle()的参数
    ret = timer_create(CLOCK_REALTIME, &evp, &timer);
    if( ret){
        perror("timer_create");
    }
   
    ts.it_interval.tv_sec = 1;
    ts.it_interval.tv_nsec = 0;
    ts.it_value.tv_sec = 3;
    ts.it_value.tv_nsec = 0;
    ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);
    if( ret )
    {
        perror("timer_settime");
    }

    while(1);

}

ref:

Linux 系统上最常用的定时器 - 知乎

Linux时间子系统之(三):用户空间接口函数

深入学习定时器 | AlloyTeam

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值