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;
}