陈硕在《Linux多线程服务端编程:使用muduo C++网络库》中说到(4.10多线程和signal):多线程程序中,使用signal的第一原则就是不要使用signal。原因是信号处理函数的复杂性和限制性,以及中断处理的困难,可能导致正确程序编写的困难,在这里陈硕举例signal handler函数中修改全局变量但是由于编译器优化导致修改不能被立刻看到的情况,以及多线程中掩码的考虑和signal hander中不能通过codition variable来通知其他线程,不能再信号处理函数中创建其他线程等。
但是在之前的定时函数的实现中,我都是用alarm+信号处理函数+统一事件源,来处理定时任务。
所以需要了解一下timerfd_*系列系统调用,以及gettimeofday()函数。
虽然网上文章不少,但是笔者认为吸收别人的意见并用自己的话写下来和只看别人的文章是不一样的,加上每个人的侧重点也不同,所以有必要写下来。
参考文章:
linux timerfd系列函数总结
Linux的timerfd分析
当定时器超时时候,定时器对象代表的文件描述符可读,也就是可以用read函数读取,而且要
注意read读取的是uint64_t类型的值,如果不是read可能会读取失败。
uint64_t exp = 0;
int ret = read(tmfd, &(exp), sizeof(uint64_t));
头文件
#include
timerfd_create创建一个定时器对象,并返回对应的文件描述符
随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变CLOCK_MONOTONIC会是一个更好的选择。//设置定时器
struct itimerspec {
struct timespec it_interval; /* Interval for periodic timer (定时间隔周期)*/
struct timespec it_value; /* Initial expiration (第一次超时时间)*/
};
//
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds */
};
it_interval不为0则表示是周期性定时器,it_value和it_interval都为0表示停止定时器
从第一秒开始,每一秒触发一次。
#include
#include
#include "fcntl.h"
#include "unistd.h"
#include
#include
#include
using namespace std;
int main(){
int tmfd;
int ret;
struct itimerspec new_value;
struct timeval tv;
gettimeofday(&tv,NULL);
new_value.it_value.tv_sec = 1;
new_value.it_value.tv_nsec = 0;
new_value.it_interval.tv_sec = 1;
new_value.it_interval.tv_nsec = 0;
//创建定时器
tmfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
if (tmfd == -1)
{
printf("timerfd_create fail\n");
return 0;
}
//用相对时间设置定时器
timerfd_settime(tmfd, 0, &new_value, NULL);
for(int i = 0; i != 10; ++i){
uint64_t exp = 0;
//由于设置为阻塞,所以read返回的时候定时器一定是被触发了
int ret = read(tmfd, &(exp), sizeof(uint64_t));
printf("%d sec, ret = %d, exp = %u\n", i, ret, exp);
}
close(tmfd);
return 0;
}