linux定时器操作

ops/2024/12/27 0:07:41/

目录

  • 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.ppmy.cn/ops/145248.html

相关文章

AI 视频:初识 Pika 2.0,基本使用攻略

网址&#xff1a;https://pika.art/ 目前 pika 2.0 免费使用&#xff0c;不过免费的期限是 12月23日 的 下午4点左右&#xff0c;在没有订阅的情况下&#xff0c;生成速度大致十几分钟左右&#xff0c;并且 Pikaffect 这个在 pika 2.0 使用不了&#xff0c;只能是 pika 1.5 使…

Linux零基础速成篇一(理论+实操)

前言&#xff1a;本教程适合Linux零基础学习&#xff0c;也适合Linux期末考试的小伙伴&#xff0c;从头到尾理论与实操相结合&#xff0c;让你快速对Linux进行了解和掌握。 一、Linux概述 为什么要学习Linux操作系统&#xff1f; 完全免费-开源 任何用户均可下载使用 安全…

leetcode hot100 翻转二叉树

226. 翻转二叉树 已解答 简单 相关标签 相关企业 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val0, leftNone, rightNone): # …

docker commit生成的镜像瘦身

1、清除宿主系统的docker资源 docker system prune -a --volumes 2、清理容器内系统的临时文件和缓存 # 删除包管理器缓存 apt-get clean rm -rf /var/lib/apt/lists/* # 删除日志文件 rm -rf /var/log/* # 删除临时文件 rm -rf /tmp/* 3、安装docker squash工具&#xff0…

梳理你的思路(从OOP到架构设计)_设计模式Factory Method模式

目录 1、Factory Method模式 2、范例&#xff1a; Android FM(工厂)模式 3、Android里处处可见的FM模式的应用 1、Factory Method模式 誰來創建<T>的對象呢?例如&#xff0c; 剛才的Template Method模式內含一個EIT造形&#xff0c;那麼&#xff0c; 請問&#xff…

探索大语言模型的世界:入门指南

随着人工智能技术的飞速发展&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为诸多行业关注的焦点。从自然语言处理到生成式人工智能&#xff0c;LLMs 正在改变我们与技术互动的方式。如果你刚刚接触大语言模型&#xff0c;不知道从何下手&…

uni-app开发订单列表页面

目录 一:功能描述 二:功能实现 一:功能描述 订单列表页面包含三个部分,最上面显示订单的状态信息,可以根据订单进行切换,中间显示订单的商品和价格信息,最下面显示订单的操作按钮,可以根据不同的状态操作订单。 二:功能实现 1:状态切换 <view class="nav-…

32位MCU主控智能电表方案

智能电表作为电网数据采集的核心设备&#xff0c;承担着至关重要的角色。它主要用于采集、计量和传输原始的电能数据&#xff0c;确保电力系统的高效运行。该设备配备了多种通讯接口&#xff0c;如RS485和以太网&#xff0c;使得用户能够轻松进行用电检测、集中抄表以及电力管理…