POSIX Timer API 的使用

文章介绍了POSIX定时器API的使用,包括timer_create、timer_settime、timer_gettime和timer_delete等函数,以及如何设置不同的通知方式如信号和线程回调。示例代码展示了如何创建定时器、设置超时时间,并在信号或线程中处理定时器到期事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POSIX Timer API 使用

所需头文件
#include <signal.h>
#include <time.h>
链接库-lrt
API
//创建定时器
int timer_create(clockid_t clockid, struct sigevent *sevp,timer_t *timerid);
//设置定时器时间
int timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
//获取定时器的剩余时间
int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
删除定时器
int timer_delete(timer_t timerid);

timer_create

创建定时器,clockid指定时钟源类型,可选的有
CLOCK_REALTIME真实时间,会受到用户更改时间的影响,慎用。
CLOCK_MONOTONIC单调时间,自系统开机后持续增加。如果不想让程序收到用户修改时间的影响,可以用这个。
CLOCK_PROCESS_CPUTIME_ID (since Linux 2.6.12)当前进程耗费的CPU时间
CLOCK_THREAD_CPUTIME_ID (since Linux 2.6.12)当前线程耗费的CPU时间
sevp,常用字段

#ifdef POSIX_TIMER_USE_THREAD 
    sev.sigev_notify = SIGEV_THREAD;            /* Notify via thread */
    sev.sigev_notify_function = threadFunc;     /* Thread start function */
    sev.sigev_notify_attributes = NULL;
#else
    sev.sigev_notify = SIGEV_SIGNAL;/* Notify via SIGNAL */
    sev.sigev_signo = SIG;
#endif
    sev.sigev_value.sival_ptr = &_cond;

sev.sigev_notify可以设置的参数类型
SIGEV_NONE
不通知,用户使用timer_gettime检测定时器的剩余时间

SIGEV_SIGNAL
以信号通知。在创建的时候指定时器到时间后用到的信号。定时器创建的参数如下
sev.sigev_notify = SIGEV_SIGNAL;/* Notify via SIGNAL */
sev.sigev_signo = SIG;
SIGEV_THREAD
指定一个回调函数,定时器到时间后系统调用在新线程调用此回调函数。

SIGEV_THREAD_ID (Linux-specific)
指定一个回调函数,定时器到时间后系统调用在指定线程调用此回调函数。

timer_settime

timer_settime:设置定时器时间
使用struct itimerspec类型来定义时间,此结构体定义如下

 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 */
 };
it_value指的是定时器首次定时时间,it_interval则是定时器超时后下一次的超时时间,为0则表明定时器为单次定时器。
此函数也可以关闭定时器,只要传入为0的struct itimerspec即可。
#include <iostream>
#include <thread>
#include <pthread.h>
#include "unistd.h"
#include <signal.h>
#include <time.h>
#include "cstdio"
#include <cstdlib>
#include "cstring"
#include<sys/syscall.h>
#include <sys/types.h>
#define POSIX_TIMER_USE_THREAD 1
#define POSIX_TIMER_USE_SIGNAL 2
#define POSIX_TIMER_USE_THREAD_ID 3
#define POSIX_TIMER_EXPIRATION POSIX_TIMER_USE_THREAD
#define POSIX_TIMER_EXPIRATION_TYPE_SIGNAL (POSIX_TIMER_EXPIRATION == POSIX_TIMER_USE_SIGNAL)
#define POSIX_TIMER_EXPIRATION_TYPE_THREAD (POSIX_TIMER_EXPIRATION == POSIX_TIMER_USE_THREAD)
#define POSIX_TIMER_EXPIRATION_TYPE_THREAD_ID (POSIX_TIMER_EXPIRATION == POSIX_TIMER_USE_THREAD_ID)


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


#define PRINT_THREAD() do{printf("%s:%lx\n",__FUNCTION__, (long)pthread_self());}while(0)
#define CLOCKID CLOCK_REALTIME
pthread_cond_t _cond; //实现从队列中获取结点的同步条件变量
static int var=0;
static bool idle_thread_exit=false;
static void
handler(int sig, siginfo_t *si, void *uc)
{
    int ret=0;
    /* Note: calling printf() from a signal handler is not safe
        (and should not be done in production programs), since
        printf() is not async-signal-safe; see signal-safety(7).
        Nevertheless, we use printf() here as a simple way of
        showing that the handler was called. */
    var=1;
    printf("Caught signal %d\n", sig);
    if(0!=(ret=pthread_cond_broadcast((pthread_cond_t*)si->si_value.sival_ptr))){
        fprintf(stderr,"pthread_cond_broadcast failed(%s)!\n", strerror(ret));
    }
    //print_siginfo(si);
    //signal(sig, SIG_IGN);
    // pthread_cond_broadcast(&_cond);
    // pthread_cond_signal();
}
static void threadFunc(union sigval sv)
{
#if POSIX_TIMER_EXPIRATION_TYPE_THREAD_ID
    idle_thread_exit =true;
#endif
    var=1;
    PRINT_THREAD();
    // pthread_cond_signal((pthread_cond_t*)sv.sival_ptr);
	pthread_cond_broadcast((pthread_cond_t*)sv.sival_ptr);

}
/*
gettid()这个函数不可以在程序中直接使用,它是Linux本身的一个函数,
但是:仅包含#include <sys/types.h>,然后使用,编译时会报该函数未定义之类的错误!
解决方案:
我们可以自已定义实现方法,如下:
#include <sys/syscall.h>  //添加上此头文件
*/
pid_t gettid()
{
    return syscall(SYS_gettid);    
}
int main(int argc, char *argv[])
{
    int ret=0;
    pid_t idle_thread_tid;
   
    pthread_mutex_t _mutex; //保护队列操作的互斥量
    struct sigevent sev;
    timer_t timerid;
    struct itimerspec ts;
#if POSIX_TIMER_EXPIRATION_TYPE_SIGNAL
    struct sigaction sa;
    sigset_t mask;
#endif
    pthread_mutex_init(&_mutex, NULL);
    pthread_cond_init(&_cond, NULL);
    
#if POSIX_TIMER_EXPIRATION_TYPE_SIGNAL
    printf("POSIX Timer Sample use signal.\n");
    printf("Blocking signal %d\n", SIG);
    sigemptyset(&mask);
    sigaddset(&mask, SIG);
    if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
        errExit("sigprocmask");

    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    printf("Establishing handler for signal %d\n", SIG);
    if (sigaction(SIG, &sa, NULL) == -1)
        errExit("sigaction");
#elif POSIX_TIMER_EXPIRATION_TYPE_THREAD
    printf("POSIX Timer Sample use thread.\n");
#endif




    printf("pid:%d\n",getpid());
    PRINT_THREAD();
    auto f = [&](std::thread *t,int sleep_time){
        PRINT_THREAD();
        sleep(sleep_time);
        printf("thread:%lx run!\n",(long)t->native_handle());
        pthread_mutex_lock(&_mutex);
        while(var==0){
           pthread_cond_wait(&_cond, &_mutex);
        }
        pthread_mutex_unlock(&_mutex);
        printf("thread:%lx exit!\n",(long)t->native_handle());
    };
#if POSIX_TIMER_EXPIRATION_TYPE_THREAD_ID

    auto idlethreadfun = [&](std::thread *t,int sleep_time){
        printf("idle thread:%lx run!\n",(long)t->native_handle());
        PRINT_THREAD();
        sleep(sleep_time);
        idle_thread_tid=gettid();
        while(!idle_thread_exit){
            std::this_thread::sleep_for(std::chrono::seconds(sleep_time));
        }
        printf("idle thread:%lx exit!\n",(long)t->native_handle());
    };

    std::thread idlethread=std::thread(idlethreadfun,&idlethread,1);
#endif


    std::thread t1=std::thread(f,&t1,1);
    std::thread t2=std::thread(f,&t2,2);
    // t1.detach();
    // t2.detach();

#if POSIX_TIMER_EXPIRATION_TYPE_THREAD
    sev.sigev_notify = SIGEV_THREAD;            /* Notify via thread */
    sev.sigev_notify_function = threadFunc;     /* Thread start function */
    sev.sigev_notify_attributes = NULL;
#elif POSIX_TIMER_EXPIRATION_TYPE_SIGNAL
    sev.sigev_notify = SIGEV_SIGNAL;/* Notify via SIGNAL */
    sev.sigev_signo = SIG;
#elif POSIX_TIMER_EXPIRATION_TYPE_THREAD_ID
    memset(&sev,0,sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD_ID;            /* Notify via thread */
    //sev.sigev_notify_function = threadFunc;     /* Thread start function */
    //sev.sigev_notify_attributes = NULL;
    sev._sigev_un._tid = idle_thread_tid;
#endif
    sev.sigev_value.sival_ptr = &_cond;
    if (timer_create(CLOCKID, &sev, &timerid) == -1)
        errExit("timer_create");

    memset(&ts,0,sizeof(ts));
    ts.it_value.tv_sec = 10 ;
	ts.it_value.tv_nsec =0;// ms * 1000000;

    if(timer_settime(timerid,0,&ts,NULL) == -1){
		perror("timer_settime");
		return -1;
	}
#if POSIX_TIMER_EXPIRATION_TYPE_SIGNAL
    printf("Unblocking signal %d\n", SIG);
    if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
        errExit("sigprocmask");
#endif
    if(t1.joinable())
        t1.join();

    if(t2.joinable())
        t2.join();
#if POSIX_TIMER_EXPIRATION_TYPE_THREAD_ID
    if(idlethread.joinable())
        idlethread.join();
#endif
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);

    printf("-----exit-------\n");
    return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值