定时器
1. 结构体详解
- timer_t :timerid 定时器ID;
- struct sigevent sev;
- struct itimerspec it;
struct sigevent
{
int sigev_notify; //通知方法
int sigev_signo; //信号类别
union sigval sigev_value; //通过通知传递的数据 下有详解
void (*sigev_notify_function)(union sigval); //用于线程运行的函数
void *sigev_notify_attributes; //上面那个线程的属性
pid_t sigev_notify_thread_id; //线程id
}
union sigval //通过通知传递的数据
{
int sival_int;
void *sival_ptr;
}
struct itimerspec
{
struct timespec it_interval; //循环时间
struct timespec it_value; //初次到期的时间间隔 就是延迟多长时间开始
}
it.it_interval.tv_sec=1;//时间s
it.it_interval.tv_nsec=0;//纳秒us.
it.it_value.tv_sec=0;
it.it_value.tv_nsec=0;
2.函数详解
1. timer_creat():创建一个新的timer;并且指定定时器到时间通知装置
2. timer_delete():删除一个timer
3. timer_gettime():获取剩余时间
4. timer_settime():开始或停止某个定时器
5. timer_getoverrun():获取丢失的定时器通知个数
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
clock_id: 依据的时钟
evp:定时器到期产生的异步通知
*timerid:定时器id
int timer_delete(timer_t timerid)
失败返回-1,,成功返回0表示该timeid指定了无效的定时器
int timer_gettime(timer_t timerid,struct itimerspec *value);
取得一个定时器的超限运行次数:
有可能一个定时器到期了,而同一定时器上一次到期时产生的信号还处于挂起状态,未被处理。
在这种情况下,其中的一个信号可能会丢失。
这就是定时器超限。程序可以通过调用timer_getoverrun来确定一个特定的定时器出现这种超限的次数。
定时器超限只能发生在同一个定时器产生的信号上。
由多个定时器,甚至是那些使用相同的时钟和信号的定时器,所产生的信号都会排队而不会丢失。
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);
new_value->it_value 如果大于 0,表示启动定时器,Timer 将在 it_value 这么长的时间过去后到期,此后每隔 it_interval 便到期一次。
如果 it_value 为 0,表示停止该 Timer。
有些时候,应用程序会先启动用一个时间间隔启动定时器,随后又修改该定时器的时间间隔,这都可以通过修改 new_value 来实现;
假如应用程序在修改了时间间隔之后希望了解之前的时间间隔设置,则传入一个非 NULL 的 old_value 指针,
这样在 timer_settime() 调用返回时,old_value 就保存了上一次 Timer 的时间间隔设置。
多数情况下我们并不需要这样,便可以简单地将 old_value 设置为 NULL,忽略它。
int timer_getoverrun(timer_t timerid);
执行成功时,timer_getoverrun()会返回定时器初次到期与通知进程(例如通过信号)定时器已到期之间额外发生的定时器到期次数。(没太懂)
举例来说,在我们之前的例子中,一个1ms的定时器运行了10ms,则此调用会返回9。
如果超限运行的次数等于或大于DELAYTIMER_MAX,则此调用会 返回DELAYTIMER_MAX。
执行失败时,此函数会返回-1并将errno设定会EINVAL,这个唯一的错误情况代表timerid指定了无效的定时器。
3. Clock ID详解
timer_creat()的参数
1. CLOCK_REALTIME:系统保存的时间,系统时间遭到篡改的时候可能会导致定时器的不准时
2. CLOCK_MONOTONIC:以当前实际走过的时间
3. CLOCK_PROCESS_CPUTIME_ID:进程实际运行的时间,即拿到cpu资源运行的时间(针对多进程)
4. CLOCK_THREAD_CPUTIME_ID:线程实际运行的时间,即拿到cpu资源运行的时间(针对多线程)
4. sev->sigev_notify到期通知的方法
1. SIGEV_SIGNAL: 发送由sev->sigev_signo指定的信号到调用进程,sigev_signo此时指定信号的类别
2. SIGEV_NONE: 什么都不做,只提供通过timer_gettime和timer_getoverrun查询超时信息。
3. SIGEV_THREAD:以sev->sigev_notification_attributes为线程属性创建一个线程, 在新建的线程内部以sev->sigev_value为参数调用evp->sigev_notification_function。
说白了就是每次创建一个新线程,用线程运行sigev_notify_function函数,传入sigev_value作为参数,每次sigev_value修改可以改变定时发送的数据。
sigev_notify_attributes如果非空,则是一个指向pthread_attr_t 的指针,用来设置线程的属性(比如stack大小,detach状态)
4. SIGEV_THREAD_ID: 发送sev->sigev_signo到sev->sigev_notify_thread_id指定线程id,该线程实际存在且属于当前的调用进程。
注意
SIGEV_THREAD_ID 通常和 SIGEV_SIGNAL 联合使用,这样当 Timer 到期时,系统会向由 sigev_notify_thread_id 指定的线程发送信号,否则可能进程中的任意线程都可能收到该信号
sev->sigev_signo :
- 可靠信号与不可靠信号,实时信号与非实时信号
- 可靠信号就是实时信号 : 信号支持排队,不会丢失,发多少次,就可以收到多少次
- 不可靠信号就是非实时信号:信号不支持排队,信号可能会丢失,发送多次相同信号,进程只接收一次
- [SIGRTMIN,SIGRTMAX]区间内的都是可靠信号
一般可填可不填,不太懂
timer_create: 与配置绑定
define CLOCKID CLOCK_REALTIME//系统真实时间
if(timer_create(CLOCKID,&sev,&timerid)==-1)//定时器ID与sev结构体绑定
{
perror("fail to timer_create");
exit(-1);
}
timer_settime: 与时间绑定
if(timer_settime(timerid,0,&it,NULL)==-1)
{
perror("fail to timer_settime");
exit(-1);
}
使用案例:
timer_t timerid
struct sigevent sev;
struct itimerspec its;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = timerid;
sev.sigev_value.sival_int=2
sev.sigev_notify_function = send_dog;
sev.sigev_notify_attributes = NULL;
if(timer_create(CLOCK_REALTIME,&sev,&timerid)==-1)
{
perror("fail to timer_create");
exit(-1);
}
its.it_value.tv_nsec=10;
its.it_value.tv_sec=0;
its.it_interval.tv_sec =1;
its.it_interval.tv_nsec =0;
if(timer_settime(timerid, 0, &its, NULL) == -1)
{
perror("fail to timer_settime");
exit(-1);
}
void send_dog(union sigval v)
{
cout<<"test:"<<v.sival_int<<endl;//每次运行这个函数的线程都不一样
}
2274

被折叠的 条评论
为什么被折叠?



