linux c的四种定时方式(sleep/usleep/select/ioctl)

Posted chris83

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux c的四种定时方式(sleep/usleep/select/ioctl)相关的知识,希望对你有一定的参考价值。

1:sleep()

最小单位秒。
使用sleep/ulseep/select时,因为线程会进入休眠状态,再唤醒, 若单次执行问题不大,若是循环执行次数较多,则差别很大。

2:ulseep()

最小单位微秒。

3:select()

最小单位微秒,再循环体内使用时,每次使用都需要赋值。

4:rtc()

 使用ioctl控制。

5:以上四种方法的使用示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>   // gettimeofday sleep usleep
#include <sys/types.h> // open
#include <sys/stat.h>  // open
#include <fcntl.h>     // open
#include <errno.h>      // error
#include <unistd.h>     // close
#include <linux/rtc.h>  // rtc_commadn RTC_IRQP_SET / RTC_PIE_ON / RTC_PIE_OFF
#include <sys/ioctl.h>  // ioctl
/**g++ -o timer_test time_test.cc*/

/* 定义log输出宏 */
#define DEB_LOG(fmat,...)  printf("%s:%d_%s() "fmat"
", 
    __FILE__, __LINE__, __FUNCTION__,##__VA_ARGS__)

/*设定时钟频率,频率可用范围是2~8192,一定要是2的n次方,8192时,一次约122微妙,*/
#define FREQ 8192
#define USEC_PER_SECOND 1000000
/*根据输入的等待待时间(毫秒),计算循环次数*/
#define CALC_CNT(millseconds) (millseconds * 1000.0 / USEC_PER_SECOND * FREQ + 0.5)


struct timeval tvs, tve;
void showTime(int startStop, long sleepT, const char* msg) {
    if (1 == startStop) {
        gettimeofday(&tvs, 0);   // 记录定时器开始时间
    } else {
        gettimeofday(&tve, 0);   // 记录定时器结束时间
        DEB_LOG("%s:    [%ldus] [%ldus]", msg, sleepT,
                (tve.tv_sec - tvs.tv_sec) * 1000000LL
                        + (tve.tv_usec - tvs.tv_usec));
    }
}

/* * 打开RTC时钟设备
 * freq: RTC 时钟的频率
 * fd:  读取RTC时钟的fd * */
int openRTC(int freq, int* fd) {
    /* 打开 RTC 时间设备 */
    *fd = open("/dev/rtc", O_RDONLY);
    if (*fd < 0) {
        DEB_LOG("open /dev/rtc NG, errno=%d msg=%s", errno, strerror(errno));
        return -1;
    }

    /* 设定 RTC 的时钟频率   2~8192Hz,最小精度为123微秒*/
    if (ioctl(*fd, RTC_IRQP_SET, freq) < 0) {
        DEB_LOG("ioctl(RTC_IRQP_SET)");
        close(*fd);
        return -1;
    }
    /* 启动 RTC 时钟  */
    if (ioctl(*fd, RTC_PIE_ON, 0) < 0) {
        DEB_LOG("ioctl(RTC_PIE_ON)");
        close(*fd);
        return -1;
    }
    return 0;
}

/* * 关闭RTC时钟设备
 * fd:  读取RTC时钟的fd * */
void closeRTC(int fd) {
    /* 关闭 RTC 时钟计时  */
    ioctl(fd, RTC_PIE_OFF, 0);
    /* 关闭 RTC 装置 */
    close(fd);
}

/*使用ioctl的情况下的,计时器函数*/
int rtcTimer(int millseconds, int fd) {
    int loopNum = CALC_CNT(millseconds);
    unsigned long data = 0;
    for (int i = 0; i < loopNum; i++) {
        /*read一次的时间 = 1秒/时钟频率 (频率范围 2~8192,最小精度为123微秒)*/
        if (read(fd, &data, sizeof(unsigned long)) < 0) {
            return -1;
        }
    }
    return 0;
}

int main(int argc, char* argv[]) {
    int sleepMs = 3;       // ms
    int sleepLoop = 5000;
    long sleepT = sleepMs * sleepLoop * 1000;
    /*##############  sleep ############################*/
    sleep(1);       // sleep 1秒

    /*##############  使用 usleep 做定时 #################*/
    showTime(1,sleepT,"usleep");
    for (int i = 0; i < sleepLoop; ++i) {
        usleep(sleepMs * 1000); // 等待单位微秒
    }
    showTime(2,sleepT,"usleep");

    /*##############  使用 select 做定时 ###################*/
    showTime(1,sleepT,"select");
    struct timeval wait_time;
    gettimeofday(&tvs, 0);
    for (int i = 0; i < sleepLoop; i++) {
        wait_time.tv_sec = 0;                     //
        wait_time.tv_usec = sleepMs * 1000;       //微妙
        select(0, NULL, NULL, NULL, &wait_time);  //使用select等待   ,10
    }
    showTime(2,sleepT,"select");

    /*##############  使用实时时钟 RTC 做定时 ################*/
    // 打开 RTC 时钟
    int fd;
    int ret = openRTC(FREQ, &fd);
    if (0 != ret) {
        DEB_LOG("openRTC error");
        return -1;
    }
    /* 使用 RTC 时钟计时   */
    showTime(1,sleepT,"ioctl RTC");
    for (int i = 0; i < sleepLoop; ++i) {
        rtcTimer(sleepMs, fd); /* 调用定时器函数 */
    }
    showTime(2,sleepT,"ioctl RTC");
    closeRTC(fd); //关闭 RTC 时钟
    return 0;
}

 

6:执行后的时间差别

test.cc:33_showTime() usleep:    [15000000us] [15812772us]
test.cc:33_showTime() select:    [15000000us] [15795666us]
test.cc:33_showTime() ioctl RTC:    [15000000us] [15259142us]

 


以上是关于linux c的四种定时方式(sleep/usleep/select/ioctl)的主要内容,如果未能解决你的问题,请参考以下文章

CMDB实现的四种方式

CMDB实现的四种方式

java -jar后台启动的四种方式

Linux网卡配置的四种模式以及防火墙设置的四种方式(CentOS 7.4)未完成

Java线程池的四种创建方式

TCP的四种定时器