Linux 定时器

发布时间:2023年12月17日

alarm() 函数实现定时功能

alarm()函数的签名

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

参数1 是你想定时的秒数。

返回值是在你调用这个函数的时刻,上一次的 alarm() 所剩余的秒数。例如,你上一次调用了 alarm(10),7秒钟以后你再次调用了alarm(6),那么在 alarm(6) 时返回的值就是 3 。

alarm() 的定时是一次性的,若想实现循环定时功能,则需要手动在本次定时结束时再次启动 alarm() 定时
[如代码实现中,第一次设定定时器后,经过3s后才调用sig_alarm_handler函数,因为是一次性的,所以在sig_alarm_handler函数中, int remaing = alarm(2);继续使用alarm函数]
alarm() 在定时到时后会发出一个 SIGALRM 信号,所以还需要我们拦截这一信号才能接收到定时回调结果。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>

static int counter;

void sig_alarm_handler(int);

time_t current_time;
struct tm *time_info;
char timeString[64]; // 用于存储格式化后的时间

void output_time()
{
    // 获取当前时间
    time(&current_time);
    // 将time_t类型的时间转换为tm结构
    time_info = localtime(&current_time);

    // 格式化时间输出为年-月-日 时:分:秒
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", time_info);
    printf("当前时间: %s\n", timeString);
}

int main()
{

    printf("pid: %d\n", getpid());

    // sighandler_t *pre = signal(SIGALARM, sig_alarm_handler);
     //拦截定时器信号。
    __sighandler_t *pre = signal(SIGALRM, sig_alarm_handler);
    printf("signal() return ret address:%p,my sig_alm_handler:%p\n", pre, sig_alarm_handler);

    //设定定时器。
    int remaing = alarm(3);
    output_time();
    printf("alarm remaing:%d\n", remaing); // remaing 应该是0才对。
    counter = 0;

    while (1)
    {
        // usleep(500);
    }

    //主动关闭定时器。
    alarm(0);
    output_time();

    return 0;
}

void sig_alarm_handler(int sig_num)
{
    printf("%s,signal number:%d,couter:%d\n", __FUNCTION__, sig_num, counter);
    if (sig_num == SIGALRM)
    {
        counter++;
        int remaing = alarm(2);
        printf("re-alarm remaing:%d\n", remaing);
        output_time();
    }
}

在这里插入图片描述

setitimer() 函数实现定时功能

系统调用:

在这里插入图片描述
setitimer一个进程中只能有一个 下一个会覆盖前一个的定时 想一个进程多个定时器只能自己实现。
setitimer() 不支持在同一进程中同时使用多次以支持多个定时器。

linux系统给每个进程提供了3个定时器

每个定时器在各自不同的域里面计数。当任何一个timer计数到结束了,系统就发送一个信号(signal)给该进程,同时计数器重置。
一共支持以下3中计数器形式:
  ITIMER_REAL 在real time中计数器减1,然后等计数往比后发送SIGALRM信号。
  ITIMER_VIRTUAL 当进程在执行的过程中计数,然后当计数完毕后发送SIGVTALRM信号给该进程。
  ITIMER_PROF 在该进程被执行和系统在代表该进程执行的时间都进行计数

区别和用途:
在Linux和类Unix操作系统中,ITIMER_REAL, ITIMER_VIRTUAL, 和 ITIMER_PROF 是三种不同类型的计时器,每种计时器的行为和用途有所不同。下面是这三种计时器的区别:

ITIMER_REAL (数值为0)
行为: 此计时器按实际时间(墙上时间)计数。当设定的时间到达时,它发送SIGALRM信号。
用途: 这种计时器通常用于实现真实时间的延迟或超时功能。例如,程序可能希望在特定的实时后执行某些操作。

ITIMER_VIRTUAL (数值为1)
行为: 此计时器仅在进程处于用户模式(即执行自己的代码)时计时。当设定的时间到达时,它发送SIGVTALRM信号。
用途: ITIMER_VIRTUAL用于测量进程在用户模式下花费的时间。这对于优化程序中的代码或测量特定代码块的执行时间非常有用。

ITIMER_PROF (数值为2)
行为: 此计时器在进程在用户模式以及内核模式(执行系统调用)时都计时。当设定的时间到达时,它发送SIGPROF信号。
用途: ITIMER_PROF用于进行更全面的性能分析。它可以帮助开发者了解程序在执行自己的代码和系统调用时消耗的总时间,因此广泛用于性能分析和优化。

总结来说,这三种计时器的主要区别在于它们计时的时机和触发的信号。ITIMER_REAL关注实时,适用于需要遵循实际时间的任务;ITIMER_VIRTUAL仅在进程执行用户级代码时计时,适用于代码优化;而ITIMER_PROF在进程执行用户级和系统级代码时都计时,适用于全面的性能分析。

代码实现

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

time_t current_time;
struct tm *time_info;
char timeString[64]; // 用于存储格式化后的时间

void sig_handler()
{
    exit(0);
}

void output_time()
{
    // 获取当前时间
    time(&current_time);
    // 将time_t类型的时间转换为tm结构
    time_info = localtime(&current_time);

    // 格式化时间输出为年-月-日 时:分:秒
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", time_info);
    printf("当前时间: %s\n", timeString);
}

void handler_time()
{
    printf("hello,i'm yammy\n");
    output_time();
}

void setTimeStruct()
{
    struct itimerval itime;
    itime.it_interval.tv_sec = 1; // 定时器启动后,每隔1秒将执行相应的函数
    itime.it_interval.tv_usec = 0;
    itime.it_value.tv_sec = 5; 5秒钟后将启动定时器
    itime.it_value.tv_usec = 0;

    output_time();
    printf("setitimer()\n");
    setitimer(ITIMER_REAL, &itime, NULL);
    output_time();
}

int main()
{
    output_time();
    signal(SIGINT, sig_handler);
    signal(SIGALRM, handler_time);

    setTimeStruct();
    while (1)
        ;

    return 0;
}

在这里插入图片描述

文章来源:https://blog.csdn.net/qq_42853675/article/details/134982046
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。