当前位置: 首页 > news >正文

linux定时器操作

目录

  • 1 简单示例
  • 2 timer_create方式
    • 2.1 SIGEV_SIGNAL信号方式通知
    • 2.2 SIGEV_THREAD启动线程方式通知
    • 2.3 参数


1 简单示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>void setup_timer(int seconds) {struct itimerval new_value, old_value;// 设置定时器初始值new_value.it_value.tv_sec = seconds;new_value.it_value.tv_usec = 0;// 设置定时器触发周期,0表示不重复new_value.it_interval.tv_sec = 0;new_value.it_interval.tv_usec = 0;// 设置定时器类型为ITIMER_REALsetitimer(ITIMER_REAL, &new_value, &old_value);
}void signal_handler(int sig) {if (sig == SIGALRM) {printf("Timer expired\n");}
}int main() {// 设置信号处理函数signal(SIGALRM, signal_handler);// 设置定时器,每1秒触发一次setup_timer(1);// 执行其他任务while(1) {sleep(1);}return 0;
}

2 timer_create方式

2.1 SIGEV_SIGNAL信号方式通知

当需要在定时器到期时触发一个信号,并且希望在信号处理器中执行特定的操作时使用。这是最常见的用法之一,适用于需要实时响应的应用程序

  1. 创建信号捕捉器sigaction
  2. 创建定时器timer_create
  3. 启动定时器timer_settimer
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>// 信号处理函数
void signal_handler(int signum, siginfo_t *info, void *context) {if (signum == SIGUSR1) {//使用设置的info->si_value.sival_ptr来判断定时器编号printf("Timer 1 expired, data: %p\n", info->si_value.sival_ptr);}
}int main() {struct sigevent sev1, sev2;timer_t timerid1, timerid2;// TODO 设置信号处理器struct sigaction sa;sa.sa_flags = SA_SIGINFO;  // 使用 sa_sigaction 而不是 sa_handlersa.sa_sigaction = signal_handler;sigemptyset(&sa.sa_mask);if (sigaction(SIGUSR1, &sa, NULL) == -1 || sigaction(SIGUSR2, &sa, NULL) == -1) {perror("sigaction");exit(EXIT_FAILURE);}// TODO 配置第一个定时器sev1.sigev_notify = SIGEV_SIGNAL;sev1.sigev_signo = SIGUSR1;sev1.sigev_value.sival_ptr = (void*) "Timer 1";if (timer_create(CLOCK_REALTIME, &sev1, &timerid1) == -1) {perror("timer_create for timer 1");exit(EXIT_FAILURE);}// TODO 配置第二个定时器sev2.sigev_notify = SIGEV_SIGNAL;sev2.sigev_signo = SIGUSR1;sev2.sigev_value.sival_ptr = (void*) "Timer 2";if (timer_create(CLOCK_REALTIME, &sev2, &timerid2) == -1) {perror("timer_create for timer 2");exit(EXIT_FAILURE);}// 设置定时器1到期时间struct itimerspec its1;its1.it_value.tv_sec = 5;its1.it_value.tv_nsec = 0;its1.it_interval.tv_sec = 0;its1.it_interval.tv_nsec = 0;if (timer_settime(timerid1, 0, &its1, NULL) == -1) {perror("timer_settime for timer 1");exit(EXIT_FAILURE);}// 设置定时器2到期时间struct itimerspec its2;its2.it_value.tv_sec = 10;its2.it_value.tv_nsec = 0;its2.it_interval.tv_sec = 0;its2.it_interval.tv_nsec = 0;if (timer_settime(timerid2, 0, &its2, NULL) == -1) {perror("timer_settime for timer 2");exit(EXIT_FAILURE);}// 保持程序运行while (1) {pause();}return 0;
}

2.2 SIGEV_THREAD启动线程方式通知

当需要在一个新的线程中执行某个函数来处理定时器事件时使用。这种方式提供了更多的灵活性,因为你可以执行任意复杂的任务,而不受信号处理函数的限制。

  1. 创建线程函数
  2. 创建定时器timer_create
  3. 启动定时器timer_settimer
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>// 线程函数
void* timer_thread_function(union sigval sv) {printf("Timer thread started, data: %p\n", sv.sival_ptr);// 在这里执行你的定时器任务sleep(2);return NULL;
}int main() {struct sigevent sev1, sev2;timer_t timerid1, timerid2;// 配置第一个定时器sev1.sigev_notify = SIGEV_THREAD;sev1.sigev_notify_function = timer_thread_function;sev1.sigev_value.sival_ptr = (void*) "Timer 1";if (timer_create(CLOCK_REALTIME, &sev1, &timerid1) == -1) {perror("timer_create for timer 1");exit(EXIT_FAILURE);}// 配置第二个定时器sev2.sigev_notify = SIGEV_THREAD;sev2.sigev_notify_function = timer_thread_function;sev2.sigev_value.sival_ptr = (void*) "Timer 2";if (timer_create(CLOCK_REALTIME, &sev2, &timerid2) == -1) {perror("timer_create for timer 2");exit(EXIT_FAILURE);}// 设置定时器到期时间struct itimerspec its1, its2;// 定时器1:5秒后到期its1.it_value.tv_sec = 5;its1.it_value.tv_nsec = 0;its1.it_interval.tv_sec = 0;its1.it_interval.tv_nsec = 0;if (timer_settime(timerid1, 0, &its1, NULL) == -1) {perror("timer_settime for timer 1");exit(EXIT_FAILURE);}// 定时器2:10秒后到期its2.it_value.tv_sec = 10;its2.it_value.tv_nsec = 0;its2.it_interval.tv_sec = 0;its2.it_interval.tv_nsec = 0;if (timer_settime(timerid2, 0, &its2, NULL) == -1) {perror("timer_settime for timer 2");exit(EXIT_FAILURE);}// 保持程序运行while (1) {pause();}return 0;
}

注意事项

  • 线程资源管理: 每次定时器到期都会创建一个新的线程。如果定时器频繁到期,可能会导致大量的线程被创建,从而消耗大量系统资源。在这种情况下,可以考虑使用线程池或其他资源管理机制来优化线程的创建和销毁
  • 线程安全: 如果线程函数需要访问共享资源,确保这些操作是线程安全的,可能需要使用互斥锁或其他同步机制。

2.3 参数

sigevent 结构体用于指定当定时器到期或其他事件发生时,系统应该如何通知应用程序。sigevent.sigev_notify 成员可以设置为不同的值,以选择不同的通知方式。常见的几种方式包括:
SIGEV_NONE

说明:不进行任何通知。
使用场景:当你不需要在定时器到期时收到任何通知时使用。例如,你可能只是想让定时器运行并记	录某些内部状态,而不需要立即处理。

SIGEV_SIGNAL:

说明:通过发送信号来通知。
使用场景:当需要在定时器到期时触发一个信号,并且希望在信号处理器中执行特定的操作时使用。这是最常见的用法之一,适用于需要实时响应的应用程序。
配置:需要设置 sigev_signo 为要发送的信号编号,还可以设置 sigev_value 传递额外的数据给信号处理器。

SIGEV_THREAD:

说明:通过创建一个新的线程来通知。
使用场景:当需要在一个新的线程中执行某个函数来处理定时器事件时使用。这种方式提供了更多的灵活性,因为你可以执行任意复杂的任务,而不受信号处理函数的限制。
配置:需要设置 sigev_notify_function 为要调用的函数指针,sigev_notify_attributes 可以设置线程属性(可选),sigev_value 可以传递参数给该函数。

SIGEV_THREAD_ID (POSIX.1-2008 及更高版本):

说明:通过向指定的线程发送信号来通知。
使用场景:当需要将信号发送到特定的线程而不是整个进程时使用。这种方式允许更细粒度的控制,特别是在多线程环境中。
配置:需要设置 sigev_notify_thread_id 为目标线程的线程ID,sigev_signo 为要发送的信号编号,sigev_value 可以传递额外的数据。
http://www.lryc.cn/news/508063.html

相关文章:

  • 重拾设计模式--观察者模式
  • Vue.js前端框架教程7:Vue计算属性和moment.js
  • 【游戏设计原理】22 - 石头剪刀布
  • 3-Gin 渲染 --[Gin 框架入门精讲与实战案例]
  • python小课堂(一)
  • GESP202309 二级【小杨的 X 字矩阵】题解(AC)
  • @PostConstruct注解解释!!!!
  • laya游戏引擎中打包之后图片模糊
  • 【数据结构练习题】链表与LinkedList
  • [项目代码] YOLOv8 遥感航拍飞机和船舶识别 [目标检测]
  • 移动魔百盒中的 OpenWrt作为旁路由 安装Tailscale并配置子网路由实现在外面通过家里的局域网ip访问内网设备
  • JVM对象分配内存如何保证线程安全?
  • ArcGIS计算土地转移矩阵
  • 数据库 MYSQL的概念
  • Node.js后端程序打包问题汇总(webpack、rsbuild、fastify、knex、objection、sqlite3、svg-captcha)
  • 部署 Apache Samza 和 Apache Kafka
  • xiaomiR4c openwrt
  • leetcode-128.最长连续序列-day14
  • 梳理你的思路(从OOP到架构设计)_简介设计模式
  • JAVA前端开发中type=“danger“和 type=“text“的区别
  • python 中执行from elasticsearch import Elasticsearch,AsyncElasticsearch 报错
  • 带有 Elasticsearch 和 Langchain 的 Agentic RAG
  • Jenkins持续集成部署——jenkins安装
  • 微信小程序开发入门
  • 深度学习中自适应学习率调度器
  • Phono3py hdf5文件数据读取与处理
  • React 底部加载组件(基于antd)
  • 将HTML转换为PDF:使用Spire.Doc的详细指南(一) 试用版
  • 数据结构经典算法总复习(下卷)
  • mac 安装graalvm