深入理解C语言中的POSIX定时器

news2024/12/23 23:23:43

在这里插入图片描述

引言

在Unix和类Unix系统中,定时器是一种常见的机制,用于在特定时间间隔后执行某些操作。POSIX定时器因其灵活性和功能丰富而被广泛采用。本文将深入探讨POSIX定时器的工作原理、内部机制、使用方法及其在实际开发中的应用。
在这里插入图片描述

POSIX定时器基础

POSIX定时器是一种高级定时器接口,它允许用户创建定时器并指定定时器到期时的动作。POSIX定时器支持以下特性:

  • 信号通知:定时器到期时可以发送信号。
  • 线程通知:可以使用线程安全的方式通知特定线程。
  • 周期性定时:支持一次性定时器和周期性定时器。
  • 精确定时:支持纳秒级别的精度。
创建与配置POSIX定时器

创建一个POSIX定时器需要完成以下步骤:

  1. 初始化定时器属性

    • 使用 timer_t 类型定义定时器句柄。
    • 初始化 struct sigeventstruct itimerspec 结构体。
  2. 配置信号事件

    • sigevent 结构体中设置 sigev_notify 成员来指定定时器到期时的通知方式(信号、线程、无动作)。
    • 设置 sigev_signo 成员来指定发送的信号。
    • 使用 sigev_valuesigev_ptr 来传递额外信息。
  3. 配置定时器参数

    • itimerspec 结构体中设置初始延迟时间和重复间隔时间。
    • it_interval 字段用于指定定时器重复的时间间隔。
    • it_value 字段用于指定首次触发定时器的时间。
  4. 创建定时器

    • 调用 timer_create() 函数创建定时器,传入 clock_id(如 CLOCK_REALTIME),sigevent 结构体以及定时器句柄指针。
  5. 设置定时器

    • 使用 timer_settime() 函数设置定时器的行为。
  6. 清理定时器

    • 使用 timer_delete() 函数删除定时器。
底层原理

POSIX定时器通过内核中的定时器轮询表来实现。每个定时器都有一个关联的到期时间,当当前时间达到或超过这个时间时,就会触发相应的动作。POSIX定时器的内部机制主要包括:

  • 定时器队列:内核维护一个定时器链表,其中包含所有已创建的定时器。
  • 时间更新:内核会定期检查定时器队列,如果某个定时器的到期时间已到,则触发相应的动作。
  • 信号处理:当定时器到期时,内核会发送指定的信号给目标进程或线程。
内部实现

POSIX定时器的内部实现主要依赖于内核的定时器机制。以下是其内部工作流程的概览:

  1. 创建定时器

    • 当调用 timer_create() 时,内核会在定时器队列中添加一个新的定时器条目。
    • 每个定时器条目都包含了到期时间、重复间隔、通知方式等信息。
  2. 定时器调度

    • 内核有一个定时器调度器,它定期检查定时器队列。
    • 如果有定时器的到期时间已到,调度器会将其标记为“已到期”。
  3. 触发动作

    • 对于设置为信号通知的定时器,内核会发送指定的信号给目标进程。
    • 对于设置为线程通知的定时器,内核会唤醒指定的线程。
  4. 定时器更新

    • 对于周期性定时器,在触发动作后,内核会自动更新定时器的到期时间。
    • 对于一次性定时器,内核会在触发动作后删除定时器条目。
  5. 定时器删除

    • 当不再需要定时器时,可以通过 timer_delete() 函数来删除定时器。
    • 内核会从定时器队列中移除对应的条目。
实现细节

下面是一个完整的POSIX定时器示例,展示如何创建一个每隔一秒触发一次的定时器,并使用信号处理函数打印当前时间。

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/timer.h>
#include <time.h>

// 信号处理函数
void handler(int signo, siginfo_t *info, void *ptr)
{
    // 打印当前时间
    printf("Timer expired at %s\n", ctime(&info->si_value.sival_ptr));
}

int main()
{
    struct sigevent sevp;
    struct itimerspec its;
    timer_t timerid;

    // 初始化结构体
    memset(&sevp, 0, sizeof(sevp));
    memset(&its, 0, sizeof(its));

    // 配置sigevent结构体
    sevp.sigev_notify = SIGEV_SIGNAL;  // 使用信号通知
    sevp.sigev_signo = SIGRTMIN;       // 使用实时信号SIGRTMIN
    sevp.sigev_value.sival_ptr = (void *)time(NULL);  // 记录定时器到期的时间

    // 创建定时器
    if (timer_create(CLOCK_REALTIME, &sevp, &timerid) == -1) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }

    // 配置定时器参数
    its.it_interval.tv_sec = 1;  // 设置重复间隔为1秒
    its.it_value.tv_sec = 1;     // 设置初始延迟时间为1秒

    // 设置定时器
    if (timer_settime(timerid, 0, &its, NULL) == -1) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }

    // 注册信号处理函数
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    // 主循环等待信号
    pause();

    // 清理定时器
    if (timer_delete(timerid) == -1) {
        perror("timer_delete");
        exit(EXIT_FAILURE);
    }

    return 0;
}
错误处理与高级话题

在实际开发中,还需要考虑一些高级话题:

  • 错误处理:对于每一个系统调用都需要检查返回值是否成功,并妥善处理错误。
  • 多线程环境:在多线程环境中使用POSIX定时器时,需要注意线程同步问题。
  • 性能考量:对于高负载的应用,需要评估定时器的开销并优化定时器的使用。
  • 信号处理:深入了解信号处理机制,确保信号处理函数正确地处理信号。
性能考量
  • 定时器精度:POSIX定时器可以达到纳秒级的精度,但在实际应用中,精度可能受到系统负载的影响。
  • 调度延迟:在多任务环境中,定时器的实际触发时间可能会因为调度延迟而有所偏差。
  • 内存占用:大量的定时器可能会导致较高的内存消耗。
多线程环境

在多线程环境中使用POSIX定时器时,需要注意以下几点:

  • 线程同步:如果多个线程共享定时器资源,需要使用互斥锁或其他同步机制来避免竞态条件。
  • 线程安全的通知:使用 SIGEV_THREADSIGEV_THREAD_ID 选项可以确保线程安全的通知。
结论

通过上述内容,我们不仅了解了POSIX定时器的基本用法,还深入探讨了其内部实现原理。POSIX定时器为Unix系统中的时间敏感应用提供了强大的支持,通过合理的使用,可以有效地提高应用程序的性能和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2112341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【视频讲解】Python贝叶斯卷积神经网络分类胸部X光图像数据集实例

全文链接&#xff1a;https://tecdat.cn/?p37604 分析师&#xff1a;Yuanchun Niu 在人工智能的诸多领域中&#xff0c;分类技术扮演着核心角色&#xff0c;其应用广泛而深远。无论是在金融风险评估、医疗诊断、安全监控还是日常的交互式服务中&#xff0c;有效的分类算法都是…

数据仓库理论知识

1、数据仓库的概念 数据仓库&#xff08;英文&#xff1a;Date Warehouse&#xff0c;简称数仓、DW&#xff09;&#xff0c;是一个用于数据存储、分析、报告的数据系统。数据仓库的建设目的是面向分析的集成化数据环境&#xff0c;其数据来源于不同的外部系统&#…

Git 修改Push后的Commit Message

向远程仓库push代码之后&#xff0c;在IDEA中无法直接修改Commit Message&#xff0c;需要在终端或控制台中输入以下命令&#xff08;HEAD~1中的1表示只对最后一个提交进行修改&#xff0c;因此1可以自定义&#xff09; git rebase -i HEAD~1执行完rebase指令后&#xff0c;会…

带AI功能朵米客服系统3.5无限制开心版+搭建文档

带AI功能朵米客服系统3.5无限制开心版搭建文档&#xff0c;朵米客服系统是一款全功能的客户服务解决方案&#xff0c;提供多渠道支持&#xff08;如在线聊天、邮件、电话等&#xff09;&#xff0c;帮助企业建立与客户的实时互动。该系统具有智能分流功能&#xff0c;可以快速将…

0基础跟德姆(dom)一起学AI Python进阶07-多线程_生成器

* 多进程案例 * 带参数的多进程代码**(重点)** * 查看进程的id * 演示: 进程之间数据是相互隔离的 * 多线程案例 * 入门案例 * 带参数的多线程代码**(重点)** * 演示: 线程之间数据是相互共享的 * 互斥锁 * 上下文管理器**(重点)** > 解析: with open原理, 为啥…

每日一题,力扣leetcode Hot100之198.打家劫舍

这一道题乍一看可以双层循环暴力解&#xff0c;但是仔细一想有可能最大利益并不是一家隔着一家偷&#xff0c;我可以间隔很多家偷&#xff0c;所以 这个题的思路还是有点像爬楼梯&#xff0c;用动态规划解。 首先确立动态规划的初始条件&#xff1a; 1.dp[0]nums[0]只有一家 …

企业邮箱怎么设置邮箱监控(老板监控员工邮件的方法推荐)【企业管理必备】

在现代企业中&#xff0c;电子邮件作为主要的沟通工具&#xff0c;不仅承载着日常的工作信息&#xff0c;还涉及大量机密内容。为了确保信息安全、提高工作效率&#xff0c;许多企业希望设置邮件监控&#xff0c;了解员工的邮箱使用情况。 本文将详细介绍企业邮箱如何设置邮箱…

Qt-使用qrc文件管理资源(15)

目录 qrc机制 创建qrc文件 1.在项目中创建一个qrc文件 2.导入图片到qrc文件中 2.2先设置一个前缀 2.3把刚刚使用的图片导入到资源文件中 测试结果 图片文件到哪去了&#xff1f; qrc机制 上篇文章中&#xff0c;我们提到了窗口的图片怎么用QIcon进行修改&#xff0c;…

MySQL record 01 part

更改密码&#xff1a; alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意&#xff1a; 在命令行方式下&#xff0c;每条MySQL的命令都是以分号结尾的&#xff0c;如果不加分号&#xff0c;MySQL会继续等待用户输入命令&#xff0c;直到MyS…

USB - 笔记

1.USB接口区分 2 充电宝 图中提到的各种充电协议都是用于快速充电技术的标准,适用于不同品

聚类算法指南

欢迎来到雲闪世界。 聚类是任何数据科学家必备的技能&#xff0c;因为它对解决实际问题具有实用性和灵活性。本文概述了聚类和不同类型的聚类算法。 什么是聚类&#xff1f; 聚类是一种流行的无监督学习技术&#xff0c;旨在根据相似性将对象或观察结果分组。聚类有很多有用…

c++的封装

实现my_string中可能实现的功能 #include <iostream> #include<cstring> using namespace std; class my_string {char *str; //记录c风格的字符串int size; //记录字符串的实际长度int capacit;//记录最大容量public://无参的构造函数my_string():size(0)…

护眼台灯十大排名有哪些?盘点2024年央视公认最好的护眼灯!

随着学业负担的加重和电子设备的广泛使用&#xff0c;青少年的近视问题变得日益严峻&#xff0c;近视率也在持续上升。导致近视的因素多样&#xff0c;不仅仅局限于电子屏幕的过度使用&#xff0c;还包括遗传因素、不良的用眼习惯、环境条件、营养不良以及过重的学习压力等&…

公司电脑能监控聊天记录吗?公司监控微信聊天记录的方法,一分钟速成!

在现代企业中&#xff0c;微信已经成为许多员工日常沟通的主要工具。虽然它极大地提高了工作效率&#xff0c;但也给公司管理带来了一些挑战&#xff0c;比如如何防止员工在工作时间闲聊、保护企业机密信息不外泄等。因此&#xff0c;不少公司希望对员工的微信聊天记录进行监控…

SealSuite 一站式 IT 管理与办公安全解决方案,助力出海企业夯实数字化底座

数字化办公时代&#xff0c;企业升级 IT 基础设施&#xff0c;已不再是选择题&#xff0c;而是必答题。 数字化办公时代&#xff0c;企业为何要升级 IT 基础设施&#xff1f; 随着时代变化与科技进步&#xff0c;人们的工作方式也发生了巨大变化。如今&#xff0c;远程办公、全…

FPGA编译与部署方法全方位介绍

FPGA编译与部署是FPGA开发中的核心环节&#xff0c;涉及从代码编写、调试到将设计部署到FPGA硬件的全过程。这个流程需要经过创建项目、编写FPGA VI、模拟调试、编译生成比特流文件&#xff0c;最后将设计部署到硬件上运行。编译的特点在于并行执行能力、定制化硬件实现以及复杂…

【Java数据结构】反射、枚举以及lambda表达式

&#x1f512;文章目录&#xff1a; 1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; 2.反射 2.1反射定义 2.2反射主要应用场景 2.3Class类(反射机制的起源) 2.31获取Class类 2.32Class类常用方法 2.33获得类中的成员变量 2.34使用类中的成员…

Leetcode3258. 统计满足 K 约束的子字符串数量 I

Every day a Leetcode 题目来源&#xff1a;3258. 统计满足 K 约束的子字符串数量 I 解法1&#xff1a;暴力 暴力枚举每一个子字符串&#xff0c;看是否满足 k 约束。 代码&#xff1a; /** lc appleetcode.cn id3258 langcpp** [3258] 统计满足 K 约束的子字符串数量 I*/…

WebAPI(三)、 DOM 日期对象Date;获取事件戳;根据节点关系查找节点

文章目录 DOM1. 日期对象(1)、日期对象方法(2)、时间戳(3)、下课倒计时 2. 节点操作(1)、 查找节点&#xff08;根据节点关系找&#xff09;(2)、 增加节点&#xff1a;创建create、追加append、克隆clone(3)、 删除节点remove DOM 1. 日期对象 日期对象就是用来表示时间的对…

PMP–一、二、三模–分类–14.敏捷–技巧–原型MVP

文章目录 技巧一模14.敏捷--原型法--项目生命周期--迭代型生命周期&#xff0c;通过连续的原型或概念验证来改进产品或成果。每个新的原型都能带来新的干系人新的反馈和团队见解。题目中明确提到需要反馈&#xff0c;因此原型法比较好用。23、 [单选] 一个敏捷团队的任务是开发…