Linux应用层定时器timer使用---timerfd_create()、timerfd_settime()、timerfd_gettime()

一、定时器timerfd相关函数及说明

#include <sys/timerfd.h>

int timerfd_create(int clockid, int flags);

int timerfd_settime(int fd, int flags,
				   const struct itimerspec *new_value,
				   struct itimerspec *old_value);

int timerfd_gettime(int fd, struct itimerspec *curr_value);
timerfd_create()创建一个定时器描述符timerfd
clockid时间类型一般使用CLOCK_REALTIME、CLOCK_MONOTONIC、CLOCK_BOOTTIME_ALARM(可唤醒系统),定义在time.h中如下图
flags为0或者O_CLOEXEC/O_NONBLOCK
返回值timerfd(文件描述符)
/*
 * The IDs of the various system clocks (for POSIX.1b interval timers):
 */
#define CLOCK_REALTIME			0
#define CLOCK_MONOTONIC			1
#define CLOCK_PROCESS_CPUTIME_ID	2
#define CLOCK_THREAD_CPUTIME_ID		3
#define CLOCK_MONOTONIC_RAW		4
#define CLOCK_REALTIME_COARSE		5
#define CLOCK_MONOTONIC_COARSE		6
#define CLOCK_BOOTTIME			7
#define CLOCK_REALTIME_ALARM		8
#define CLOCK_BOOTTIME_ALARM		9

timerfd_settime()用来启动或关闭fd指定的定时器
fdtimerfd_create函数返回的定时器文件描述符timerfd
flags1代表设置的是绝对时间;为0代表相对时间
new_value指定新的超时时间,设定new_value.it_value非零则启动定时器,为零关闭定时器,如果new_value.it_interval为0,则定时器只定时一次,即初始那次,否则之后每隔设定时间it_interval超时一次
old_value不为null,则返回定时器这次设置之前的超时时间
timerfd_gettime()获得定时器距离下次超时还剩下的时间。如果调用时定时器已经到期,并且该定时器处于循环模式(设置超时时间时it_interval不为0),那么调用此函数之后定时器重新开始计时

二、 使用read读取timefd超时事件通知的说明

read(2)
If  the  timer  has  already expired one or more times since its settings were last modified using 
timerfd_settime(), or since the last successful read(2), then the buffer given to read(2) returns 
an unsigned 8-byte integer (uint64_t) containing the number of expirations that have occurred.  
(The returned value is in host byte order, i.e., the native byte order for integers on the host machine.)

If no timer expirations have occurred at the time of the read(2), then the call either blocks until 
the next timer expiration, or fails with the error EAGAIN if the file descriptor has been made 
nonblocking (via the use of the fcntl(2) F_SETFL oper‐ation to set the O_NONBLOCK flag).

A read(2) will fail with the error EINVAL if the size of the supplied buffer is less than 8 bytes.

翻译过来是:当定时器超时,read读事件发生即可读,返回超时次数(从上次调用timerfd_settime()启动开始或上次read成功读取开始),它是一个8字节的unit64_t类型整数,如果定时器没有发生超时事件,则read将阻塞;若timerfd为阻塞模式,否则返回EAGAIN 错误(O_NONBLOCK模式);如果read时提供的缓冲区小于8字节将以EINVAL错误返回。

三、timefd程序实例

该实例在Linux系统下可使用man手册查看“man timerfd_create”,在man手册该条说明的最下方有示例代码以及测试结果。

#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>        /* Definition of uint64_t */

#define handle_error(msg) \
	   do { printf(msg); exit(EXIT_FAILURE); } while (0)

static void print_elapsed_time(void)
{
   static struct timespec start;
   struct timespec curr;
   static int first_call = 1;
   int secs, nsecs;

   if (first_call) 
   {
      first_call = 0;
      if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
	   handle_error("clock_gettime");
   }

   if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
      handle_error("clock_gettime");

   secs = curr.tv_sec - start.tv_sec;
   nsecs = curr.tv_nsec - start.tv_nsec;
   if (nsecs < 0) 
   {
	   secs--;
	   nsecs += 1000000000;
   }
   printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}


int main(int argc, char *argv[])
{
   struct itimerspec new_value;
   int max_exp, fd;
   struct timespec now;
   uint64_t exp, tot_exp;
   ssize_t s;

   if ((argc != 2) && (argc != 4)) 
   {
	   ssize_t s;
	   printf("%s %d\n",__FUNCTION__, __LINE__);
	   if ((argc != 2) && (argc != 4)) 
	   {
		   fprintf(stderr, "%s init-secs [interval-secs max-exp]\n", argv[0]);
		   handle_error("argc argv is error");
	   }
   }

   if (clock_gettime(CLOCK_REALTIME, &now) == -1)
   {
      handle_error("clock_gettime");
   }

   /* Create a CLOCK_REALTIME absolute timer with initial
	  expiration and interval as specified in command line */

   new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
   new_value.it_value.tv_nsec = now.tv_nsec;
   if (argc == 2) {
	   new_value.it_interval.tv_sec = 0;
	   max_exp = 1;
   } else {
	   new_value.it_interval.tv_sec = atoi(argv[2]);
	   max_exp = atoi(argv[3]);
   }
   new_value.it_interval.tv_nsec = 0;

   fd = timerfd_create(CLOCK_REALTIME, 0);
   if (fd == -1)
	   handle_error("timerfd_create");

   if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
	   handle_error("timerfd_settime");

   print_elapsed_time();
   printf("timer started\n");

   for (tot_exp = 0; tot_exp < max_exp;) {
	   s = read(fd, &exp, sizeof(uint64_t));
	   if (s != sizeof(uint64_t))
		   handle_error("read");

	   tot_exp += exp;
	   print_elapsed_time();
	   printf("read: %llu; total=%llu\n",
			   (unsigned long long) exp,
			   (unsigned long long) tot_exp);
   }

   exit(EXIT_SUCCESS);

}

四、实例测试

编译下上面程序为timerfd_app,后面带3个参数,第一个参数为5代表第一次定时器超时时间为5s,第二个参数为后续该周期定时器的超时时间,这里设置周期定时器为3s,第三个参数为本程序最多监控的超时次数(这个参数无所谓,只是为了打印显示),这里设置为100。

root@ubuntu:/home/book/Desktop# ./timerfd_app 5 3 100
0.000: timer started
5.000: read: 1; total=1
8.001: read: 1; total=2
11.001: read: 1; total=3
14.002: read: 1; total=4
^Z                                    #type control-Z to suspend the program
[1]+  Stopped                 ./timerfd_app 5 3 100
root@ubuntu:/home/book/Desktop# fg    # Resume execution after a few seconds
./timerfd_app 5 3 100
37.679: read: 7; total=11
38.001: read: 1; total=12
41.004: read: 1; total=13
44.001: read: 1; total=14
^C                                    # type control-C to suspend the program
root@ubuntu:/home/book/Desktop# 

应用程序设置了一个定时器首次超时时间5s,后续间隔3s的重复定时器。read返回值为超时次数,正常每次的超时次数都为1,但是当使用ctrl+z暂停应用23s后再重启恢复应用运行,read读取的超时次数为7,与实际相符合,程序中total值打印的是超时次数的总和。

我们可根据man手册的这个示例代码学习应用层定时器的相关使用,大家有兴趣也可以看下内核里面定时器的使用Linux内核定时器—init_timer()、add_timer()与mod_timer()使用

要在青龙面板中安装faker3,你可以按照以下步骤进行操作: 1. 首先,在你的群晖上创建一个挂载文件夹,可以使用文件管理(File Station)进行创建。 [1] 2. 确保你的群晖已经安装了Docker,并在控制面板中启动了SSH功能,并设置端口为22。 [2] 3. 通过SSH连接到你的群晖,并执行以下命令来安装faker3容器: ``` docker exec -it Faker-QL bash -c "$(curl -fsSL https://yanyu.ltd/https://github.com/yanyuwangluo/VIP/blob/main/Scripts/sh/1customCDN.sh)" ``` 注意要替换命令中的容器名称为你自己的容器名称。 [2] 4. 至此,你已经成功安装了faker3在青龙面板中。 对于更多关于faker3的详细信息以及项目地址,你可以参考。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [群晖安装青龙面板docker+Faker一键拉库部署+j1900配置](https://blog.csdn.net/weixin_52568491/article/details/127827002)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [青龙面板仓库合集(不断更新)](https://blog.csdn.net/liu52365/article/details/121233533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值