IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Linux环境下的setitimer的延时/定时器的使用 -> 正文阅读

[系统运维]Linux环境下的setitimer的延时/定时器的使用

〇、背景

??linux C嵌入式开发编程中,经常会遇到精度要求比较高的周期性的定时事件,对于一般性要求 1ms 级别的精度,linux下可以使用 select() 函数实现,但是 select() 有一个弱点就是其 定时的误差会累积,运行到一定程度的时候,实际误差可能已经超出了允许的范围,那么在这种情况,setitimer() 函数可以解决误差累积这样的问题。

一、简介

??setitimer() 函数是一个比较常用的函数,可以用来作为定时器,或者实现延时功能,其精确度为 ms 级别,相比于 select() 或者 sleep() 族函数功能,setitimer() 在运行期间将尽量保持平均时间误差为 1ms,这取决于系统计时器分辨率和系统负载,定时时间到期后,将生成一个信号(signal)并重置计时器。如果在进程处于活动状态时计时器到期(对于 ITIMER_VIRTUAL 始终为真),则信号将在生成时立即传递。否则,信号发送将被抵消一小段时间,具体取决于系统加载。

??setitimer() 工作机制是,先对 it_value 进行倒计时,当 it_value 为的数值减为 0 时触发信号。然后再将为 it_value 重置 it_interval,之后继续对 it_value 倒计时,如此往复,当 it_value0 或 计时器到期且 it_interval0 时计时器停止运行。

??所以基于此机制,setitimer() 既可以用来作为 延时器 使用,也可以作为 定时器 使用。

二、函数说明

??最重要的需要说明就是,在一个进程中只能有一个 setitimer() 函数的调用,下一个函数的调用会覆盖前一个的计时,是不支持在同一进程中同时使用多次以支持多个定时器的功能的。/font>

2.1 函数原型

??在ubuntu 16.04环境下,setitimer()getitimer() 函数原型如下所示。

#include <sys/time.h>

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
              struct itimerval *old_value);

2.1.1 setitimer函数说明

函数名称:
??setitimer

函数功能:
??将指定的计时器设置为 new_value 中的值
??如果 old_value 不为 NULL,则计时器的旧值存储在那里

函数参数:
??which:计时器的类型,可选的类型如下描述
??new_value:要设置的计时器的新的值
??old_value:计时器的下一次到期的剩余时间,与 getitimer() 返回的信息相同
????????一般情况此参数用处不大,设置为 NULL 即可
函数返回:
????成功,返回 0
????出错,返回 -1,并适当设置 errno
函数说明:
??计时器从 it_value 递减到零,生成一个信号,然后重置为 it_interval。设置为零的计时器(it_value 为零或计时器到期且 it_interval 为零)停止。

2.1.2 getitimer函数说明

函数名称:
??getitimer

函数功能:
??获取 which 指定的计时器的下一次到期的剩余时间

函数参数:
??which:计时器的类型,与函数 setitimer() 参数相同

??curr_value:获取到的下一次到期的剩余时间的输出指针
函数返回:
????成功,返回 0
????出错,返回 -1,并适当设置 errno
函数说明:
??参数 curr_value 指向的结构的字段 it_value 的子字段设置为计时器上剩余的时间量,如果计时器被禁用,则设置为零。 it_interval 字段设置为定时器间隔(周期);在该字段(的两个子字段)中返回的值为零表示这是一个单次计时器。

2.1.3 计时器类型说明

??作为 setitimergetitimer 函数通用的计数器的类型,其可选的值有如下三个。

  • ITIMER_REAL:以系统真实的时间进行递减计算,定时时间到期时发送 SIGALRM 信号

  • ITIMER_VIRTUAL:仅在该进程进程执行时的时间来递减计算,定时时间到期时发送 SIGVTALRM 信号

  • ITIMER_PROF:以该进程在用户态下和内核态下执行的时间来递减计算。与 ITIMER_VIRTUAL 结合使用,此计时器通常用于分析应用程序在用户和内核空间中花费的时间,定时器到期时发送 SIGPROF 信号。

2.1.4 函数错误说明

??函数 setitimergetitimer 可能在调用时发生错误情况,其主要的错误有如下两种情况。

  • EFAULTnew_valueold_valuecurr_value 不是有效的指针。

  • EINVAL :不是 ITIMER_REALITIMER_VIRTUALITIMER_PROF 之一;或 new_value 指向的结构中的 tv_usec 字段之一包含 0999999 范围之外的值。

2.2 参数itimerval结构说明

??函数 setitimergetitimer 的时间参数均为 struct itimerval 类型,其结构体定义如下所示。

struct itimerval {
    struct timeval it_interval; /* 周期性定时器的间隔 */
    struct timeval it_value;    /* 距离下次到期的时间 */
};

struct timeval {
    time_t      tv_sec;         /* 秒 */
    suseconds_t tv_usec;        /* 微秒 */
};

??由上面的代码可以,itimeval 结构体又是由两个 timeval 结构体组成,timeval 包括 tv_sectv_usec 两部分。其中 tv_sec 为秒,tv_usec 为微秒(即 1/1000000 秒)。tv_sectv_usec 在确定计时器的持续时间时都很重要。

四、源码测试

??基于上面的描述,我们简单的编写一个用于定时器的测试程序,主要实现的功能是,每隔100ms在终端输出信息,包括当前的时间。示例代码入下所示。

#include <errno.h>    /* for errno */
#include <signal.h>   /* for signal */
#include <stdio.h>    /* for printf */
#include <stdlib.h>   /* for EXIT_FAILURE */
#include <string.h>   /* for strerror */
#include <sys/time.h> /* for setitimer */
#include <unistd.h>   /* for _exit pause */

void signalHandler(int signo)
{
    struct timeval tm;
    /* 获取当前的时间戳 */
    gettimeofday(&tm, NULL);

    switch (signo)
    {
    case SIGALRM:
        printf("Get the SIGALRM signal! time = %ld.%03ld\n",
               tm.tv_sec, tm.tv_usec / 1000);
        break;
    case SIGVTALRM:
        printf("Get the SIGVTALRM signal! time = %ld.%03ld\n",
               tm.tv_sec, tm.tv_usec / 1000);
        break;
    case SIGPROF:
        printf("Get the SIGPROF signal! time = %ld.%03ld\n",
               tm.tv_sec, tm.tv_usec / 1000);
        break;
    }
}

int main(int argc, char *argv[])
{
    /* 定义设置的时间结构体 */
    struct itimerval new_value = {0};

    /* 设置信号的处理方式 */
    signal(SIGALRM, signalHandler);

    /* 启动定时器的时间 */
    new_value.it_value.tv_sec = 0;
    new_value.it_value.tv_usec = 100000;
    /* 定时器的间隔时间 */
    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_usec = 100000;

    /* 以系统真实的时间来计算,将送出SIGALRM信号 */
    if (setitimer(ITIMER_REAL, &new_value, NULL) < 0)
    {
        /* 函数调用返回错误 */
        printf("Setitimer Failed : %s\n", strerror(errno));
        /* 标准退出 */
        _exit(EXIT_FAILURE);
    }

    /* 进入无限循环 */
    while (1)
    {
        /* 进程主动挂起,等待信号唤醒 */
        pause();
    }

    return 0;
}

五、测试效果图

??编译上述程序并运行,程序执行的效果如下图5.1所示。

图5.1 程序执行效果图


??好啦,如果对本文的内容有任何疑问或者建议,请随时联系并欢迎讨论,由于本人学识与精力有限,难免会有一些错误,欢迎大佬指出并斧正。如果你觉得此文章对你有帮助,烦请帮忙点个赞鼓励一下,你的肯定将是我继续女里坚持的动力。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:35:01  更:2022-05-24 18:36:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:21:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码