Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction

这篇具有很好参考价值的文章主要介绍了Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.alarm函数:设置发送信号的闹钟

通过 man 2 alarm 查看alarm函数的详细信息。

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

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

功能:设置定时器(闹钟)。从调用这个函数开始进行倒计时,倒计时结束之后(变为0),函数会给当前的进程发送SIGALARM信号。

参数:

seconds: 倒计时的时长,单位:秒。如果参数为0,定时器无效(不进行倒计时,不发信号)。取消一个定时器,通过alarm(0)。

返回值: 之前没有定时器,返回0;之前有定时器,返回之前的定时器剩余的时间。

SIGALARM信号:

默认终止当前的进程,每一个进程都有且只有唯一的一个定时器。

alarm(10);  -> 返回0

过了1秒

alarm(5);   -> 返回9

测试代码:

#include <stdio.h>
#include <unistd.h>

int main() {

    int seconds = alarm(5);
    printf("seconds = %d\n", seconds);  // 0

    sleep(2);
    seconds = alarm(2);    // 不阻塞
    printf("seconds = %d\n", seconds);  // 3

    while(1) {
    }  //alarm该函数是不阻塞的,如果不设置这个,这个程序就结束了,看不到SIGALARM信号的效果,还有两秒 才能看到

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

使用alarm函数测试电脑一秒钟能数多少个数

alarm和setitimer(ITIMER_PROF) 共享同一个定时器。即alarm的定时时间包含的是:用户+系统内核的运行时间

进行文件的IO操作会比较浪费时间,因此在执行的时候 ./alarm1 >> a.txt 写道这个文件中,向终端输出会消耗文件IO的时间。

此外需要说明的是,定时器与进程的状态无关,无论进程处于什么状态,alarm都会计时

测试代码:

#include <stdio.h>
#include <unistd.h>

int main() {    

    alarm(1);  //1秒后进程终止

    int i = 0;
    while(1) {
        printf("%i\n", i++);
    }

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

通过vim 打开a.txt,然后shift + G到最后一行,可以看到1秒钟在1000万左右,当然向文件中写入也会花费时间,真实的情况比这还要高。

2.setitimer函数

通过 man 2 setitimer 命令查看setitimer的详细描述

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
                        struct itimerval *old_value);

这些系统调用提供了对间隔计时器的访问,也就是说,这些计时器最初在将来的某个时间点过期,之后(可选地)定期过期。当计时器过期时,将为调用进程生成一个信号,并将计时器重置为指定的间隔(如果间隔非零)。

功能:

设置定时器(闹钟)。可以替代alarm函数。精确到微妙us,并可以实现周期性定时

参数:

which: 定时器以什么时间定时

  • ITIMER_REAL  :这个计时器以真实时间(即挂钟)倒数。在每次到期时,生成一个SIGALRM信号。(常用,这个真实时间包括很多其他的处理时间)

  • ITIMER_VIRTUAL  :该计时器根据进程消耗的用户模式CPU时间进行倒计时。(该度量包括进程中所有线程所消耗的CPU时间。)在每次到期时,生成一个SIGVTALRM信号。

  • ITIMER_PROF  :这个计时器根据进程消耗的总(即用户和系统)CPU时间进行计数。(该度量包括进程中所有线程所消耗的CPU时间。)在每次到期时,生成一个SIGPROF信号。

new_value: 设置定时器的属性,是一个结构体类型

struct itimerval {      // 定时器的结构体
    struct timeval it_interval;  // 每个阶段的时间,即间隔时间 2
    struct timeval it_value;     // 延迟多长时间执行定时器  10
    };


struct timeval {        // 时间的结构体
    time_t      tv_sec;     //  秒数     
    suseconds_t tv_usec;    //  微秒    精确到微妙
    };

过10秒后,每个2秒定时一次

old_value :记录上一次的定时的时间参数,一般不使用,指定NULL

返回值:成功返回0, 失败返回-1并设置错误号

测试代码:实现过3秒后,每隔2秒钟定时一次

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

// 过3秒以后,每隔2秒钟定时一次
int main() {

    struct itimerval new_value;

    // 设置间隔的时间2秒
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;


    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");  //立马执行这个

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar(); //获取键盘录入,什么也不做,否则还不到3秒程序就结束了
    //在获取键盘录入时,进程处于阻塞态,但是定时器与进程的状态无关,
    //无论进程处于什么状态,都会计时

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

我们发现,执行这个程序之后,3秒钟之后,这个程序就截止了,似乎没有每间隔2秒定时一次。原因是,当3秒钟之后,会向进程发送SIGALRM信号,进程收到这个信号后终止。因此,并没有执行每隔2秒定时一次这样的操作。这就需要信号捕捉函数了!!!捕捉这个3秒之后的信号,不让它杀死当前进程。

3.signal信号捕捉函数

通过man 2 signal 查看signal函数的详细描述

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

The  behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux.  Avoid its use: use sigaction(2) instead. (signal()的行为在不同的UNIX版本之间是不同的,在不同的Linux版本之间也是不同的。避免使用它:使用sigaction(2)代替。)

功能:简单来说就是 捕捉到某个信号,然后执行一些处理(可以是系统自带的,也可以是自定义的函数)

signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a  programmer-defined  function  (a  "signal  handler"). (将信号signum的处置设置为handler,它可以是SIG_IGN, SIG_DFL,或者是程序员定义的函数(“信号处理程序”)的地址。)

参数:

signum: 要捕捉的信号

handler: 捕捉到信号要如何处理

  • SIG_IGN : 忽略这个信号,什么也不做

  • SIG_DFL : 使用信号默认的行为,相当于没有捕捉

  • 自定义(回调函数):这个函数是由内核调用,程序员只负责写,捕捉到信号后如何去处理信号。

回调函数:(类似于C++中的仿函数)

需要程序员实现,提前准备好的,函数的类型根据实际需求,看函数指针的定义

不是程序员调用,而是当信号产生,由内核调用

函数指针是实现回调的手段,函数实现之后,将函数名放到函数指针的位置就可以了。

返回值:

成功,返回上一次注册的信号处理函数的地址。第一次调用返回NULL

失败,返回SIG_ERR,设置错误号

 SIGKILL   SIGSTOP不能被捕捉,不能被忽略。(SIGKILL是强制杀死进程,不能捕捉它,如果一旦捕捉并设置为SIG_IGN,那么这个进程就结束不了了)

测试代码:过3秒以后,每隔2秒钟定时一次

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

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    // 注册信号捕捉
    // signal(SIGALRM, SIG_IGN);
    // signal(SIGALRM, SIG_DFL);
    // void (*sighandler_t)(int); 函数指针,int类型的参数表示捕捉到的信号的值。
    signal(SIGALRM, myalarm);  //信号捕捉函数要提前设置好,就相当于打猎一样,要提前设置好陷阱。

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar();

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

3秒钟之后,捕捉到了SIGALRM信号,然后每隔2秒,再次捕捉到SIGALRM信号。

4.sigaction信号捕捉函数

通过man 2 sigaction查看sigaction函数的具体信息

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

功能:

The  sigaction()  system  call  is used to change the action taken by a process on receipt of a specific signal.  (See signal(7) for  an  overview of signals.) sigaction()系统调用用于更改进程在接收到特定信号时所采取的操作。(信号的概述见信号(7)。) 【检查或者改变信号的处理,实现信号捕捉】

参数:

signum : 需要捕捉的信号的编号或者宏值(信号的名称);signum  specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.

If act is non-NULL, the new action for signal signum is installed  from act.  If oldact is non-NULL, the previous action is saved in oldact.如果act为非null,则从act安装信号signum的新动作。如果oldact为非null,则先前的操作保存在oldact中。

act :捕捉到信号之后的处理动作

oldact : 上一次对信号捕捉相关的设置,一般不使用,传递NULL

返回值:成功0,失败-1

参数 act 和 oldact是结构体类型

The sigaction structure is defined as something like:

           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

struct sigaction {

        // 函数指针,指向的函数就是信号捕捉到之后的处理函数

        /*

        sa_handler specifies the action to be associated with signum and may be SIG_DFL          for  the  default  action, SIG_IGN to ignore this signal, or a pointer to a signal handling         function.  This function receives the signal number as its only argument.sa_handler

        指定与signum相关联的操作,默认操作可以是SIG_DFL,忽略该信号的SIG_IGN,或者指向信号处理函数的指针。这个函数接收信号号作为它的唯一参数。

        */

        void     (*sa_handler)(int);

        // 不常用

        void     (*sa_sigaction)(int, siginfo_t *, void *);

        // 临时阻塞信号集,在信号捕捉函数执行过程中,临时阻塞某些信号。

        sigset_t   sa_mask;


 

        // 使用哪一个信号处理对捕捉到的信号进行处理

        // 这个值可以是0,表示使用sa_handler,也可以是SA_SIGINFO表示使用sa_sigaction

        //On  some  architectures  a  union  is  involved:  do not assign to both sa_handler and sa_sigaction.在某些体系结构中涉及到联合:不要同时分配给sa_handler和sa_sigaction。

        int        sa_flags;


 

        // 被废弃掉了

        void     (*sa_restorer)(void);

    };

测试代码:过3秒以后,每隔2秒钟定时一次

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

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    struct sigaction act;
    
    act.sa_handler = myalarm;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);  // 清空临时阻塞信号集,全0
   
    // 注册信号捕捉,捕捉SIGALRM信号,输出myalarm中的信号
    sigaction(SIGALRM, &act, NULL);

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    // getchar();
    while(1);

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu

通过act.sa_mask设置SIGINT信号阻塞,这样程序就不能通过ctrl c停止了:

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

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    struct sigaction act;
    
    act.sa_handler = myalarm;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);  // 清空临时阻塞信号集,全0

    sigaddset(&act.sa_mask, SIGINT);  
    // 修改内核中的阻塞信号集
    sigprocmask(SIG_BLOCK, &act.sa_mask, NULL);
    //设置在信号捕捉函数执行过程中,临时阻塞SIGINT信号。
    //这样的话ctrl c就停止不了进程了
   



   
    // 注册信号捕捉,捕捉SIGALRM信号,输出myalarm中的信号
    sigaction(SIGALRM, &act, NULL);

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    // getchar();
    while(1);

    return 0;
}

Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction,linux,服务器,ubuntu文章来源地址https://www.toymoban.com/news/detail-769023.html

到了这里,关于Linux中的alarm和setitimer定时器函数以及信号捕捉函数signal和sigaction的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • javaScript定时器函数

    js 定时器有以下两个方法: setInterval() ,setTimeout() 作用  这个函数可以将一个函数每隔一段时间执行一次 返回值  返回一个Number类型的数据,这个数字用来作为定时器的唯一标识  可以用clearInterval()关闭setInterval()

    2024年02月08日
    浏览(70)
  • Python中的定时器用法:Timer定时器和schedule库

    目录 一、引言 二、Timer定时器 1、Timer定时器的原理 2、Timer定时器的使用方法 3、Timer定时器的实际应用案例 三、schedule库 1、schedule库的原理 2、schedule库的使用方法 3、schedule库的实际应用案例 四、Timer定时器和schedule库的比较 1、功能差异 2、适用场景 五、实际应用案例 六、

    2024年01月16日
    浏览(74)
  • JS-定时器-间歇函数(一)

    定时器函数在开发中的使用场景 网页中经常会需要一种功能:每隔一段时间需要自动执行一段代码,不需要我们手动去触发 例如:网页中的倒计时 要实现这种需求,需要定时器函数 定时器函数有两种,今天我先讲间歇函数 定时器函数可以开启和关闭定时器 开启定时器 作用

    2024年01月17日
    浏览(48)
  • stm32下常用函数~中断定时器

    学习江协科技stm32基于库函数开发记录一下 代码压缩包地址:code CountSensor.h CountSensor.c main.c Encoder.h Encoder.c Timer.h Timer.c main.c Timer.h Timer.c main.c pwm.h pwm.c main.c Servo.h Servo.c main.c Motor.h Motor.c main.c ic.h ic.c main.c ic.h ic.c main.c EncoderTwo.h EncoderTwo.c main.c

    2024年02月19日
    浏览(43)
  • iOS中的3种定时器

    在iOS中有3种常见的定时器,它们可以根据不同的场景进行选择使用。 1.DispatchSourceTimer: 基于GCD实现。 2.CADisplayLink:基于屏幕刷新实现。 3.Timer:基于RunLoop实现。 DispatchSourceTimer定时器 DispatchSourceTimer定时器: 可以通过DispatchSource.makeTimerSource(queue: DispatchQueue.main)方法来创建。

    2024年02月03日
    浏览(33)
  • 51 单片机【外部中断、定时器中断、回调函数】

    ​这里的外部中断类似监听器,时时刻刻监视某引脚的电平变化;这里的定时器中断类似于定时任务,可以定时执行某函数;这里将回调函数和中断结合起来,案例里有点设计模式的味道(忘了哪个了,也可能就是感觉,关于高层不能调用低层的解决),也有点函数式编程的

    2024年02月04日
    浏览(70)
  • Linux定时器

    Linux定时器是一种 软件机制 ,用于在指定的时间间隔或特定时间点执行特定的任务。它是 基于内核的机制 ,可以用于各种应用场景,如定时任务调度、延时处理、周期性事件触发等。 运作机制(工作原理):Linux定时器的工作原理主要分为两个部分:定时器的创建和定时器

    2024年02月03日
    浏览(48)
  • Linux 内核定时器

    一、相关知识点 (一)知识点 1、内核定时器分类     1)标准定时器或系统定时器     2)高精度定时器(HRT)         头文件:#include linux/hrtimer.h 2、检查系统是否可用HRT     1)查看内核配置文件              2)查看机器         cat proc/timer_list  | grep \\\"resolution\\\" 

    2024年02月11日
    浏览(41)
  • js中的定时器 setTimeout()和setInterval()

    JavaScript 定时器,有时也称为“计时器”,用来在经过指定的时间后执行某些任务,类似于我们生活中的闹钟。 在 JavaScript 中,我们可以利用定时器来延迟执行某些代码,或者以固定的时间间隔重复执行某些代码。例如,您可以使用定时器定时更新页面中的广告或者显示一个

    2024年02月14日
    浏览(52)
  • 09_Linux内核定时器

    目录 Linux时间管理和内核定时器简介 内核定时器简介 Linux内核短延时函数 定时器驱动程序编写 编写测试APP 运行测试          学习过UCOS或FreeRTOS的同学应该知道, UCOS或FreeRTOS是需要一个硬件定时器提供系统时钟, 一般使用Systick作为系统时钟源。同理 , Linux要运行 , 也是需

    2024年02月13日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包