zoukankan      html  css  js  c++  java
  • libc timer

    libc 提供了 timer_create, timer_settime, timer_delete 等函数来创建设置定时器。

    创建定时器

    使用 timer_create 函数可以创建一个定时器, 原型如下:

    int timer_create(clockid_t clockid, struct sigevent *restrict evp,
               timer_t *restrict timerid);
    
    • clockid 用于指定测量时间的方式, 可以设为以下值:
      • CLOCK_REALTIME

        使用系统实时时钟

      • CLOCK_MONOTONIC

        一种不可设置的单调递增时钟,用于测量过去某个未指定点的时间,该时间点在系统启动后不会发生变化

      • CLOCK_PROCESS_CPUTIME_ID

        一个时钟,用于衡量(用户和系统)调用进程(所有线程)消耗的CPU时间

      • CLOCK_THREAD_CPUTIME_ID

        一个时钟,用于衡量(用户和系统)调用线程消耗的CPU时间

      • CLOCK_BOOTTIME

        CLOCK_MONOTONIC, 但不同的是: 在系统挂起后仍然测量时间

      • CLOCK_REALTIME_ALARM

        CLOCK_REALTIME 但会在系统挂起后唤醒系统, 调用者必须有 CAP_WAKE_ALARM 权限

      • CLOCK_BOOTTIME_ALARM

        CLOCK_BOOTTIME 但会在系统挂起后唤醒系统, 调用者必须有 CAP_WAKE_ALARM 权限

    • evp 用于设定定时器的处理方式及方法, evp..sigev_notify 指定处理方式, 可为以下值:
      • SIGEV_NONE

        当定时器到达时不做处理, 主动使用 timer_gettime 监听并处理

      • SIGEV_SIGNAL

        当定时器到达时发送 evp.sigev_signo 指定的信号

      • SIGEV_THREAD

        当定时器到达时, 开启一个新线程来调用 evp.sigev_notify_function 指定的函数

      • SIGEV_THREAD_ID

        当定时器到达时, 发送一个带有 evp.sigev_notify_thread_id 指定线程 id 的信号

    • timerid 定时器 id

    链接时需要带上 -lrt


    设置定时器

    使用 timer_create 函数设置定时器的间隔时间, 原型如下:

    int timer_settime(timer_t timerid, int flags,
               const struct itimerspec *restrict value,
               struct itimerspec *restrict ovalue);
    
    • timerid 创建得到的 id
    • flags 定时器标志, 设置为 TIMER_ABSTIME 时定时器下一次到达的时间为指定的绝对值与当前时钟的差值
    • value 设置定时器的时间间隔信息
    • ovalue 为上次设置的定时器间隔信息

    定时器的时间间隔信息是 struct itimerspec 类型, 原型如下:

    struct timespec {
        time_t tv_sec;                /* Seconds */
        long   tv_nsec;               /* Nanoseconds */
    };
    
    struct itimerspec {
        struct timespec it_interval;  /* Timer interval */
        struct timespec it_value;     /* Initial expiration */
    };
    
    • it_value 为第一次定时器的间隔时间
    • it_interval 为第一次之后每次定时器的间隔时间
    • tv_sec 为秒数, 值应大于 0
    • tv_nsec 为纳秒数, 应小于 1000000000

    删除定时器

    使用 timer_create 函数可以删除一个定时器, 原型如下:

    int timer_delete(timer_t timerid);
    
    • timerid 创建时得到的 id


    示例如下

    下面给出了使用信号和线程处理定时器的代码:

    #include <time.h>
    #include <signal.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    #define CLOCKID CLOCK_REALTIME
    #define SIG SIGALRM
    #define TIMER_DURATION 1000 // 1000ms
    
    static int start_signal_timer(timer_t *id, int sig, int duration);
    static int start_thread_timer(timer_t *id, int duration);
    static int do_start_timer(timer_t *id, struct sigevent *sev, int duration);
    static int stop_timer(timer_t *id);
    static void thread_handler(union sigval);
    static int setup_signal(int sig);
    static void signal_handler(int sig, siginfo_t *si, void *data);
    
    int
    main(int argc, char *argv[])
    {
            if (argc != 2) {
                    printf("Usage: %s <signal/thread>
    ", argv[0]);
                    return -1;
            }
            timer_t timerid;
            int ret = 0;
            if (strcmp(argv[1], "signal") == 0) {
                    ret = setup_signal(SIG);
                    if (ret == -1) {
                            printf("Failed to setup signal: %s
    ", strerror(errno));
                            return -1;
                    }
                    ret = start_signal_timer(&timerid, SIG, TIMER_DURATION);
            } else if (strcmp(argv[1], "thread") == 0 ){
                    ret = start_thread_timer(&timerid, TIMER_DURATION);
            }
            if (ret == -1) {
                    return -1;
            }
            printf("Create timer id: %p
    ", timerid);
            printf("Please input 'quit' to exit...
    ");
    
            char buf[1024] = {0};
            while (1) {
                    printf("Please input: ");
                    scanf("%s", buf);
                    if (strcmp(buf, "quit") == 0) {
                            break;
                    }
            }
    
            ret = stop_timer(&timerid);
            if (ret == -1) {
                    printf("Failed to delete timer: %s
    ", strerror(errno));
            }
            printf("Exit...
    ");
            return 0;
    }
    
    static int
    start_signal_timer(timer_t *id, int sig, int duration)
    {
            struct sigevent sev;
    
            // handle in thread when timeout
            memset(&sev, 0, sizeof(struct sigevent));
            sev.sigev_notify = SIGEV_SIGNAL;
            sev.sigev_signo = sig;
            sev.sigev_value.sival_int = 111;
            return do_start_timer(id, &sev, duration);
    }
    
    static int
    start_thread_timer(timer_t *id, int duration)
    {
            struct sigevent sev;
    
            // handle in thread when timeout
            memset(&sev, 0, sizeof(struct sigevent));
            sev.sigev_notify = SIGEV_THREAD;
            sev.sigev_notify_function = thread_handler;
            sev.sigev_value.sival_int = 111;
            return do_start_timer(id, &sev, duration);
    }
    
    static int
    do_start_timer(timer_t *id, struct sigevent *sev, int duration)
    {
            struct itimerspec its; // duration settings
    
            int ret = timer_create(CLOCKID, sev, id);
            if (ret == -1) {
                    printf("Failed to create timer: %s
    ", strerror(errno));
                    return -1;
            }
            printf("The timer id: %p
    ", id);
    
            // set timeout, only once
            // it_value the first timeout duration
            // it_interval the next timeout duration
            if (duration >= 1000) {
                    its.it_value.tv_sec = duration / 1000;
                    its.it_value.tv_nsec = (duration%1000) * 1000000;
            } else {
                    its.it_value.tv_nsec = duration * 1000000;
            }
            its.it_interval.tv_sec = its.it_value.tv_sec;
            its.it_interval.tv_nsec = its.it_value.tv_nsec;
    
            ret = timer_settime(*id, 0, &its, NULL);
            if (ret == -1) {
                    printf("Failed to set timeout: %s
    ", strerror(errno));
                    return -1;
            }
    
            return 0;
    }
    
    static int
    stop_timer(timer_t *id)
    {
            if (*id == 0) {
                    return 0;
            }
            return timer_delete(*id);
    }
    
    static void
    thread_handler(union sigval v)
    {
            printf("Timer arrived: %d
    ", v.sival_int);
    }
    
    static int
    setup_signal(int sig)
    {
            struct sigaction sa;
    
            sa.sa_flags = SA_SIGINFO;
            sa.sa_sigaction = signal_handler;
            sigemptyset(&sa.sa_mask);
            return sigaction(sig, &sa, NULL);
    }
    
    static void
    signal_handler(int sig, siginfo_t *si, void *data)
    {
            printf("Signal arrived: %d
    ", sig);
            printf("	Uid: %u, Pid: %u
    ", si->si_uid, si->si_pid);
            printf("	Value: %d
    ", si->si_value.sival_int);
    }


    参考链接:https://www.jianshu.com/p/dce281011799

    作者:快乐出发0220 ;Android群:151319601 ; Linux群:96394158 ;转载请注明出处 http://klcf0220.cnblogs.com/ !!!
  • 相关阅读:
    anaconda 离线安装大包
    Openpose 安装问题解决
    Linux grep log文件及find命令学习
    整理了一些常用编程软件(方便自己下载)
    Docker安装es7.6和kibana7.6(并解决Unable to revive connection: http://192.168.162.139:9200/的问题)
    Jsr303分组校验和自定义注解校验
    Spring Cloud整合Oss
    Linux:vim
    Linux:挂载命令
    SpringBoot整合SpringSecurity:集中式项目
  • 原文地址:https://www.cnblogs.com/klcf0220/p/15411623.html
Copyright © 2011-2022 走看看