zoukankan      html  css  js  c++  java
  • 一个利用信号捕获实现循环定时器代码阅读笔记


    看了一份利用捕获信号的方式,实现循环定时器的代码,重新复习了一下linux下timer编程和signal编程。

    下面对几个函数进行注释说明,便于后面查看。

    首先是创建定时器的函数:


    struct itimerspec tim;
    timer_t realTimer;
    struct sigevent event;

    1.timer_create(CLOCK_REALTIME, &event, &realTimer)
    这个函数就是创建一个定时器,与系统定时器相关,设置基于CLOCK_REALTIME的定时器,就是和系统真实时间一致。当定时器到时,内核发出设置的信号,我们就捕获这个信号进行处理。

    event.sigev_notify = SIGEV_SIGNAL;
    event.sigev_signo = SIGRTMAX;
    这两个值就是设置了信号的行为和信号值


    2.clock_gettime(CLOCK_REALTIME,&(tim.it_value));

    这个函数就是获取当前的系统时间值

    tim.it_value.tv_sec += 10;

    tim.it_interval.tv_sec = 0;
    tim.it_interval.tv_nsec = 0;

    获取时间后,设置tv_sec的值,+10 就是起一个10s后到期的定时器


    3.timer_settime(realTimer,TIMER_ABSTIME,&tim,0)

    这个函数是最后一步,设置前面创建的定时器,指定过期时间。


    原型是int timer_settime (timer_t timerid,int flags,const struct itimerspec *value,struct itimerspec *ovalue);

    struct itimerspec {
    struct timespec it_interval; /* next value */
    struct timespec it_value; /* current value */
    };

    it_value上面得知是指定的过期时间,当定时器过期时将用it_interval的值更新it_value,如果it_interval是0,定时器在过期后停止运行。


    flags是TIMER_ABSTIME,指value指定的是绝对时间,这里理解成和realtimer的绝对时间,realtimer是固定不变的(程序起来时的时间)

    这样一个定时器就创建好了,不过这时候只是一个一次性定时器,并且,到期后,是系统捕获的信号进行默认处理的,程序会直接退出,下面讲信号的捕获。


    首先,内核处理信号时有三种方式:
    一,忽略信号
    不采取任何操作。

    二,捕获并处理信号
    内核会跳到以前注册过的信号处理函数,完成函数调用后,返回捕获信号的地方继续执行

    三,执行默认操作
    一般是终止程序


    这里我们需要采用第二种方式,因为定时器到期后我们希望进行处理,并创建新的定时器,实现循环定时器。


    希望捕获信号有三种方式

    1,用sighandler_t signal (int signo, sighandler_t
    handler);函数
    注册处理函数,指定需要捕获的信号值

    当收到信号时,就会调用处理函数进行处理。


    2.int sigaction (int signo,const struct sigaction *act,struct sigaction *oldact);

    POSIX定义了sigaction系统调用,它提供更强大的信号管理能力,可以用来阻塞特定的信号接收,防止信号的漏收。

    3.sigemptyset(),sigaddset(),pthread_sigmask(),sigwait()

    event.sigev_notify = SIGEV_SIGNAL;
    event.sigev_signo = SIGRTMAX;

    if (sigemptyset(&sigmask) == -1 || sigaddset(&sigmask,SIGRTMAX) == -1)
    {
    printf("set sig error ");
    return 0;
    }

    pthread_sigmask(SIG_BLOCK,&sigmask,NULL);

    for(;;)
    {
    if (sigwait(&sigmask,&sig) == -1)
    {
    printf("end ");
    return;
    }


    .....
    //创建新的定时器
    tim.it_value.tv_sec += 5;
    tim.it_value.tv_nsec = 0;

    if (timer_settime(realTimer,TIMER_ABSTIME,&tim,0) == -1)
    {
    printf("timer set error ");

    return 0;
    }
    }


    第三种方式是利用sigaddset将给的的信号值放入信号集,然后调用pthread_sigmask(SIG_SETMASK,&sigmask,NULL);

    pthread_sigmask函数的用法是:在多线程的程序里,希望只在主线程中处理信号

    pthread_sigmask,第一个参数取值可以是:
    SIG_BLOCK: 结果集是当前集合参数集的并集
    SIG_UNBLOCK: 结果集是当前集合参数集的差集
    SIG_SETMASK: 结果集是由参数集指向的集


    sigwait 暂定调用线程, 直到 set 中定义的某个信号递达调用线程.
    sigwait 所等待的信号必须在所有线程中阻塞, 而不仅仅是调用线程. 在多线程的程序里,希望只在主线程中处理信号,可以使用


    摘录网上一位兄台的笔记
    “在多线程代码中,总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。
    而不是signal或者sigaction等函数。因为在一个线程中调用signal或者sigaction等函数会改变所有线程中的信号处理函数,而不是仅仅改变调用signal/sigaction的那个线程的信号处理函数。”

    “pthread_sigmask函数:
    每个线程均有自己的信号屏蔽集(信号掩码),可以使用pthread_sigmask函数来屏蔽某个线程对某些信号的
    响应处理,仅留下需要处理该信号的线程来处理指定的信号。实现方式是:利用线程信号屏蔽集的继承关系
    (在主进程中对sigmask进行设置后,主进程创建出来的线程将继承主进程的掩码)”


    总的来说就是利用pthread_sigmask,阻塞需要捕获的信号,sigwait监听该信号,当信号发生时,进行下面的处理。

    因为该代码运行在多线程,所以采用了第三种方式,以前只接触过前两种,这次又学习到了。

  • 相关阅读:
    1.20
    1.18
    4.16python安装
    4.15Android学习
    4.14Android学习
    4.13Android学习
    4.12Android学习
    4.11Android学习
    4.10Android学习
    4.09Android学习
  • 原文地址:https://www.cnblogs.com/yemeng/p/5220965.html
Copyright © 2011-2022 走看看