热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

linux使用select实现精确定时器详解

本文讲述如何使用select实现超级时钟。使用select函数,我们能实现微妙级别精度的定时器。同时,select函数也是我们在编写非阻塞程序时经常用到的一个函数
在编写程序时,我们经常会用到定时器。首先看看select函数原型如下:
代码如下:

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

参数说明:
slect的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。
select的第二三四个参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件。所以每次调用select前都需重新初始化fdset。
timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。
利用select实现定时器,需要利用其timeout参数,注意到:
 1)select函数使用了一个结构体timeval作为其参数。
 2)select函数会更新timeval的值,timeval保持的值为剩余时间。
如果我们指定了参数timeval的值,而将其他参数都置为0或者NULL,那么在时间耗尽后,select函数便返回,基于这一点,我们可以利用select实现精确定时。
timeval的结构如下:
代码如下:

struct timeval{
long tv_sec;/*secons*
long tv_usec;/*microseconds*/
}

我们可以看出其精确到microseconds也即微妙。
一、秒级定时器
代码如下:

void seconds_sleep(unsigned seconds){
    struct timeval tv;
    tv.tv_sec=seconds;
    tv.tv_usec=0;
    int err;
    do{
       err=select(0,NULL,NULL,NULL,&tv);
    }while(err<0 && errno==EINTR);
}

 二、毫秒级别定时器
代码如下:

void milliseconds_sleep(unsigned long mSec){
    struct timeval tv;
    tv.tv_sec=mSec/1000;
    tv.tv_usec=(mSec%1000)*1000;
    int err;
    do{
       err=select(0,NULL,NULL,NULL,&tv);
    }while(err<0 && errno==EINTR);
}

 三、微妙级别定时器
代码如下:

void microseconds_sleep(unsigned long uSec){
    struct timeval tv;
    tv.tv_sec=uSec/1000000;
    tv.tv_usec=uSec%1000000;
    int err;
    do{
        err=select(0,NULL,NULL,NULL,&tv);
    }while(err<0 && errno==EINTR);
}

现在我们来编写几行代码看看定时效果吧。
代码如下:

#include
#include
#include
int main()
{
    int i;
    for(i=0;i<5;++i){
    printf("%d\n",i);
    //seconds_sleep(1);
    //milliseconds_sleep(1500);
    microseconds_sleep(1900000);
    }
}

 注:timeval结构体中虽然指定了一个微妙级别的分辨率,但内核支持的分别率往往没有这么高,很多unix内核将超时值向上舍入成10ms的倍数。此外,加上内核调度延时现象,即定时器时间到后,内核还需要花一定时间调度相应进程的运行。因此,定时器的精度,最终还是由内核支持的分别率决定。
分类: Linux
推荐阅读
  • Unix与Linux的起源与发展
    本文详细探讨了Unix与Linux的操作系统起源,从自由软件运动的兴起,到Linux内核的诞生,全面解析了这两款操作系统的发展历程及其对现代计算技术的影响。 ... [详细]
  • 本文详细介绍了将本地计算机和服务器从CentOS 7.2或7.3版本升级到7.4的过程,包括必要的准备步骤、执行升级的具体命令以及验证升级是否成功的检查方法。 ... [详细]
  • Linux中使用Shell脚本获取网络配置信息
    本文提供了一组Shell命令,用于在Linux系统中提取IP地址、子网掩码、MAC地址及默认网关等关键网络配置信息。 ... [详细]
  • VS Code 中 .vscode 文件夹配置详解
    本文介绍了 VS Code 中 .vscode 文件夹下的配置文件及其作用,包括常用的预定义变量和三个关键配置文件:launch.json、tasks.json 和 c_cpp_properties.json。 ... [详细]
  • 去控件化在线文档处理,推动高效信创办公环境
    探讨在线文档处理去控件化的趋势及其对构建高效信创办公生态的影响。 ... [详细]
  • 本文详细介绍了如何在Ubuntu操作系统中安装和配置Maven,包括必要的环境准备和验证步骤。 ... [详细]
  • Mac环境下Java与Ant自动化构建环境搭建指南
    本文详细介绍了如何在Mac操作系统上为测试工程师搭建Java和Ant开发环境,包括环境变量配置等关键步骤。 ... [详细]
  • 本文详细介绍了Linux系统中的三个主要分区:启动分区、交换分区和根分区的功能与特点,以及常见的文件类型、文件搜索方法和常用符号的使用。此外,还深入解析了mkdir和rm命令的具体应用。 ... [详细]
  • 重新审视Kubernetes的必要性
    近期,我注意到不少人误以为我是Kubernetes的推广者。实际上,我只是分享了一些适合用Kubernetes解决的案例。本文旨在探讨Kubernetes的适用场景,并提供一些替代方案。 ... [详细]
  • UMPlatForm.NET 5.1 版本数据字典管理功能解析
    本文介绍了 UMPlatForm.NET 5.1 版本中的数据字典管理模块,探讨了该模块如何支持平台的数据共享与管理,以及如何通过用户和角色权限来增强系统的安全性。 ... [详细]
  • 万事起于配置开发环境
    万事起于配置开发环境 ... [详细]
  • 本文将详细介绍在Linux环境下挂载U盘的方法和步骤,帮助用户更好地理解和操作Linux系统下的外部存储设备。 ... [详细]
  • 本文深入探讨了分布式文件系统的核心概念及其在现代数据存储解决方案中的应用,特别是针对大规模数据处理的需求。文章不仅介绍了多种流行的分布式文件系统和NoSQL数据库,还提供了选择合适系统的指导原则。 ... [详细]
  • 本文档提供了详细的MySQL安装步骤,包括解压安装文件、选择安装类型、配置MySQL服务以及设置管理员密码等关键环节,帮助用户顺利完成MySQL的安装。 ... [详细]
  • 本文详细探讨了 HAProxy 的基本概念及其与 LVS(Linux Virtual Server)的比较,特别是在内核空间与用户空间的工作差异。文章还深入介绍了 HAProxy 独有的数据结构——弹性二叉树,以及其在高并发场景下的表现。 ... [详细]
author-avatar
zhuzhu-2012_389
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有