定时器与超时的设置

2023-05-16

      • 一、相关时间函数
          • 1. gettimeofday()
          • 2. time()
          • 3. clock()
      • 二、间隔定时器
          • 1. setitimerval()
          • 2. getitimerval()
          • 3. 实时定时器的使用
      • 三、为阻塞操作设置超时
          • 1. alarm()
          • 2. 给read()设置读超时


一、相关时间函数

1. gettimeofday()

获取日历时间。

#include <sys/time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);
  • timeval结构体
struct timeval {
    time_t tv_sec;        // 秒
    suseconds_t tv_usec;  // 微秒(long int)
};
2. time()

返回自Epoch(格林威治标准时间1970.01.01 0:00AM)以来的秒数。

#include <time.h>

time_t time(time_t *timep);

参数timep存储返回的时间。若timep为空,则直能从函数返回值获得。

time_t t = time(NULL);
3. clock()

计时函数。返回值为从程序启动到调用该函数所占用CPU的时间,实际为CPU时钟计时单元(clock tick)数。

#include <time.h>

clock_t clock(void) ;

由于不同系统或编译器对于每秒的时钟单元数定义不同,所以直接输出会有所不同。所以还定义了常量CLOCKS_PER_SEC,表示一秒钟会有多少个时钟计时单元,其定义如下:

#define CLOCKS_PER_SEC ((clock_t)1000)

CLOCKS_PER_SEC在Linux 4.15.0-32-generic系统上数值为1000000。


二、间隔定时器

1. setitimerval()

使用系统调用setitimer()来创建间隔定时器,这种定时器会在一定时间后到期,并可以在到期后每隔一段时间到期一次。

#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value,
                struct itimerval *old_value);
  • which参数的可选项:

    • ITIMER_REAL
      以真实时间计时,到期产生SIGALARM信号

    • ITIMER_VIRTUAL
      以虚拟时间(用户模式下CPU时间)计时

    • ITIMER_PROF
      创建profiling定时器以内核态与用户态CPU时间总和计时,到期会产生SIGPROF信号

  • itimerval结构体

struct itimerval {
    struct timeval it_interval;  // 间隔定时器的间隔时间
    struct timeval it_value;     // 定时器到期的剩余时间
};

其中,it_value表示距离定时器到期的剩余时间,it_interval记录定时器的周期时间(或不进行周期性定时,it_interval中两个值同为0时表示没有周期性定时,即一次性定时器)。若进行周期性定时,则在每次到时后会将it_interval重新存储倒计时的间隔时间。

2. getitimerval()

获取定时器当前状态。

#include <sys/time.h>

int getitimerval(int which, struct itimerval *curr_value );

curr_value存储定时器当前状态,其内容与调用setitimerval()返回的old_value内容相同。

3. 实时定时器的使用
/* 运行说明:
    ./timer 1 800000 1 0
    第二个参数为倒计时的秒数,第三个参数为倒计时的微秒数,
    第四个参数为定时器间隔时间的秒数,第五个参数为定时器间隔时间的微秒数

    后四个参数可以省略,默认为 2 0 0 0
*/

#include <iostream>
#include <string.h>
#include <sys/time.h>
#include <signal.h>

static volatile sig_atomic_t gotAlam = 0;

/* 打印时间,includeTimer表示是否为第一次打印,第一次只打印前两个数字 */
static void displayTimes( const char *msg, bool includeTimer ) {
    struct itimerval itv;
    static struct timeval start;  // 起始状态
    struct timeval curr;  // 当前状态
    static int callNum = 0;  // 当前函数被调用次数

    if( callNum == 0 ) {
        if( gettimeofday( &start, nullptr ) == -1 ) {
            perror( "gettimeofday" );
        }
    }

    /* 每20行打印一次提示信息 */
    if( callNum % 20 == 0 ) {
        printf("       Elapsed    Value    Interval\n");
    }

    if( gettimeofday( &curr, NULL ) == -1 ) {
        perror( "gettimeofday" );
    }
    printf("%-7s %6.2f", msg, curr.tv_sec - start.tv_sec + (curr.tv_usec - start.tv_usec) / 1000000.0 );

    /* 可以打印后两个数字 */
    if( includeTimer ) {
        if( getitimer( ITIMER_REAL, &itv ) == -1 ) {
            perror( "getitimer" );
        }
        printf("  %6.2f  %6.2f", itv.it_value.tv_sec + itv.it_value.tv_usec / 1000000.0, 
                itv.it_interval.tv_sec + itv.it_interval.tv_usec / 1000000.0);
    }
    printf("\n");
    callNum++;
}

/* 信号处理函数 */
static void sigalrmHandler( int sig ) {
    gotAlam = 1;
}

int main( int argc, char **argv ) {
    struct itimerval itv;
    clock_t preClock;
    int maxSigs = 0;  // 信号触发最大次数
    int sigCnt = 0;  // 信号已触发次数
    struct sigaction sa;

    sigemptyset( &sa.sa_mask );
    sa.sa_flags = 0;
    sa.sa_handler = sigalrmHandler;
    if( sigaction( SIGALRM, &sa, NULL ) == -1 ) {
        perror( "sigaction" );
    }

    maxSigs = ( itv.it_interval.tv_sec == 0 && itv.it_interval.tv_usec == 0 ) ? 1 : 3;
    displayTimes( "start:", false );

    itv.it_value.tv_sec = (argc > 1) ? atoi( argv[1] ) : 2;
    itv.it_value.tv_usec = (argc > 2) ? atoi( argv[2] ) : 0;
    itv.it_interval.tv_sec = (argc > 3) ? atoi( argv[3] ) : 0;
    itv.it_interval.tv_usec = (argc > 4) ? atoi( argv[4] ) : 0;

    if( setitimer( ITIMER_REAL, &itv, 0 ) == -1 ) {
        perror( "setitimer" );
    }

    preClock = clock();

    while( true ) {
        while( ( clock() - preClock ) * 10 / CLOCKS_PER_SEC < 5 ) {
            /* 定时器时间到 */
            if( gotAlam ) {
                gotAlam = false;
                displayTimes( "ALARM:", true );

                sigCnt++;
                if( sigCnt >= maxSigs ) {
                    printf("That's all folk\n");
                    exit( EXIT_SUCCESS );
                }
            }
        }

        preClock = clock();
        displayTimes( "Main:", true );
    }
}

三、为阻塞操作设置超时

1. alarm()

创建一次性实时定时器。

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

seconds表示倒计时的秒数。到期后会发送SIGALARM信号。

调用alarm(0)可以屏蔽所有现有定时器。

2. 给read()设置读超时
#include <iostream>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
using namespace std;

const int BUFFER_SIZE = 200;

/* 信号处理函数 */
static void handler( int sig ) {
    printf("caught signal\n");
}

int main( int argc, char **argv ) {
    struct sigaction sa;
    char buf[BUFFER_SIZE];
    ssize_t numRead;
    int savedErrno;

    sa.sa_flags = ( argc > 2 ) ? SA_RESTART : 0;
    sigemptyset( &sa.sa_mask );
    sa.sa_handler = handler;
    if( sigaction( SIGALRM, &sa, NULL ) == -1 ) {
        perror("sigaction");
    }

    /* 设置倒计时 */
    alarm( (argc > 1) ? atoi(argv[1]) : 10 );
    numRead = read( STDIN_FILENO, buf, BUFFER_SIZE - 1 );

    savedErrno = errno;
    alarm(0);  // 将现有定时器屏蔽
    errno = savedErrno;

    if( numRead == -1 ) {
        if( errno == EINTR ) {  // read系统调用被信号打断,即收到超时信号
            printf("Read timed out\n");
        } else {
            perror("read");
        }
    } else {  // 未超时
        printf("Successful read %ld bytes : %.*s", long(numRead), int(numRead), buf);
    }

    exit(EXIT_SUCCESS);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

定时器与超时的设置 的相关文章

随机推荐

  • win10下的mysql5.7开启binglog

    log bin 61 E node exclude mysql5 7 mysql 5 7 42 binglog mysql bin binlog format 61 ROW server id 61 2 mysql 设置mysql客户端默认
  • mysql Error occurred: Cannot select database.

    问题 PS E node exclude mysql5 7 mysql 5 7 42 winx64 bin gt mysql upgrade u root p force Enter password Error occurred Cann
  • mybatis plus or and 合并写法

    int count 61 hrDeliverEmployContractService selectCount new EntityWrapper lt HrDeliverEmployContractEntity gt eq 34 pool
  • 设计模式(大大提高代码可维护性以及复用性)(持续更新)

    单例 xff08 Singleton xff09 模式 xff1a 某个类只能生成一个实例 xff0c 该类提供了一个全局访问点供外部获取该实例 xff0c 其拓展是有限多例模式 原型 xff08 Prototype xff09 模式 xf
  • 并发量、QPS 和TPS区别

    并发量 xff1a 系统同时处理的request 事务数 可以理解为 xff1a 系统同时处理的request数量 TPS xff1a 每秒处理的查询量 每秒钟request 事务 数量 可以理解为 xff1a 每秒处理的request 数
  • mysql-plus 字段验证策略fieldStrategy

    ignored 不管有没有有设置属性 xff0c 所有的字段都会设置到insert语句中 xff0c 如果没设置值 xff0c 全为null xff0c 这种在update 操作中会有风险 xff0c 把有值的更新为null not nul
  • Navicat 12 for MySQL最新版激活(注册机)

    整个过程在断网环境下 安装包也用刚下载的 转 https blog csdn net zhangli0910 article details 83785147 最新版注册机 43 Navicat下载 xff1a 链接 xff1a https
  • C_INCLUDES must be under the source or output directories

    Android项目N版本切到O版本 xff0c 同一个模块去mm xff0c 报C INCLUDES must be under the source or output directories错误 后来才找到原因 xff0c 是因为该模块
  • “MobaXterm X11 proxy: Unsupported authorisation protocol”解决方法

    服务器无法显示GUI图片问题 在解决这个问题的时候 xff0c 可能很多人都搜到了用sudo的方法 xff0c 但是在我们没有管理权限的情况下 xff0c 这个问题也是能解决的 报错信息 我的报错信息 xff1a MobaXterm X11
  • Linux 并发与竞争

    Linux是一个多任务操作系统 xff0c 肯定会存在多个任务共同操作同一段内存或者设备的情况 xff0c 多个任务甚至中断都能访问的资源叫做共享资源 xff0c 就和共享单车一样 在驱动开发中要注意对 共享资源的保护 xff0c 也就是要
  • linux man手册和设置中文版man手册

    http man he net linux 设置中文版man手册
  • win10宽带连接断网自动重连

    文章目录 1 断开网络连接 xff0c 重命名网络连接2 bat代码 xff1a 检测到断线自动重连3 设置开机自动执行3 1 方式一 xff1a 任务计划程序3 2 方式二 xff1a 用vbs代码开机运行bat 1 断开网络连接 xff
  • ubuntu20环境下使用DevStack安装Openstack-Wallaby(单节点、多节点)

    文章目录 一 单节点部署1 环境准备1 1 镜像源1 2 pip源1 3 安装依赖包 2 OpenStack安装 wallaby2 1 添加 96 stack 96 用户2 2 设置代理2 3 下载devstack xff0c 使用 96
  • 【操作系统】页面置换算法

    页面置换算法 在进程运行过程中 xff0c 若需要访问的物理块不在内存中 xff0c 就需要通过一定的方式来将页面载入内存 xff0c 而此时内存很可能已无空闲空间 xff0c 因此就需要一定的算法来选择内存中要被置换的页面 xff0c 这
  • 前端 好看实用的颜色大全(16进制)

  • 解决linux写入ntfs盘时报错:只读文件系统

    2018 10 28 更新 可能因为在挂载wimdows盘后 xff0c 强制关机造成的 xff0c 可使用 sudo ntfsfix dev 来修复 其中 xff0c 为具体哪个盘 xff0c 例如sudo ntfsfix dev sda
  • 【计算机网络】TCP IP通信处理过程

    1 数据包首部 每个分层中都会对所发送的数据附加一个首部 xff0c 其中包含了该层必要的信息 xff0c 如发送端地址 接收端地址以及协议等相关信息 2 发送数据包 1 xff09 应用程序处理 进行编码处理 xff08 相当于表示层功能
  • 【高性能定时器】 时间轮

    时间轮 简述 顾名思义 xff0c 时间轮就像一个轮子 xff0c 在转动的时候外界会指向轮子不同的区域 xff0c 该区域就可以被使用 因此只要将不同时间的定时器按照一定的方法散列到时间轮的不同槽 xff08 即时间轮划分的区域 xff0
  • 系统调用中断(EINTR)与SIGCHLD信号的处理

    一 被中断的系统调用 EINTR 的理解 1 慢系统调用是 xff1f 2 慢系统调用的类别3 EINTR产生的原因5 一般处理方法 二 SIGCHLD信号的处理 1 SIGCHLD信号的产生2 SIGCHLD信号的处理3 不处理SIGCH
  • 定时器与超时的设置

    一 相关时间函数 1 gettimeofday 2 time 3 clock 二 间隔定时器 1 setitimerval 2 getitimerval 3 实时定时器的使用 三 为阻塞操作设置超时 1 alarm 2 给read 设置读超