linux下实现定时器的三种简单方式

目录

一. sleep()和usleep()

1.sleep()

2.usleep()

3.毫秒级延时

二. signal与alarm()

三. select

四. 一些总结


一. sleep()和usleep()

        优点是简单便捷,直接调用即可,但是缺点也很明显,精度不够,特别是在系统负载比较大时,会发生超时现象。

1.sleep()

#include <unistd.h>

unsigned int sleep(unsigned int   seconds);

功能:执行挂起指定的秒数

        sleep()只能精确到秒级上。sleep()非系统调用,sleep()是在库函数中实现的,它是通过alarm()来设定报警时间,使用sigsuspend()将进程挂起在信号SIGALARM上。sleep()会令目前的进程暂停,直到达到参数seconds 所指定的时间,或是被信号所中断。

2.usleep()

#include <unistd.h>

void usleep(int     micro_seconds);

功能:把进程挂起一段时间,单位是微秒(百万分之一)

        除了时间单位为微秒以外,在使用上与sleep()差不多。但实现是不同的,sleep是用alarm实现的,所以时间单位为s ,而usleep的时间单位为us,肯定不是由alarm实现的,所以说它们的实现不同,但都是linux用的,而window下不能用,因为都是sleep和usleep都是在unistd.h下定义的。

        一般情况下,延迟时间数量级是秒的时候,尽可能使用sleep()函数。如果延迟时间为几十毫秒(1ms = 1000us),或者更小,尽可能使用usleep()函数。这样才能最佳的利用CPU时间。

3.毫秒级延时

        因为linux下没有现成的毫秒级延时,这里我们可以自己简单写一个:

#include <unistd.h>

void msleep(unsigned long     ms)
{
    struct timeval        tv;
    tv.tv_sec = ms/1000;
    tv.tv_usec = (ms%1000)*1000;

    select(0, NULL, NULL, NULL, &tv);
}

二. signal与alarm()

        使用signal函数设定SIGALRM的处理函数,然后使用alarm()定时发送SIGALRM来实现。  

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

int alarm_flag=1;

void timer(int sig)
{
    if(SIGALRM == sig)
    {
        alarm_flag = 1;
    }
    return;
}

int main()
{
    signal(SIGALRM, timer);
    
    while( alrm_flag )
    {
        alarm_flag = 0;

        printf("hello\n");
        alarm(5);
     }

    return 0;
}

#include <unistd.h>

unsigned int alarm(unsigned int         seconds);        

功能:设置信号传送闹钟

        alarm()也称为闹钟函数,alarm()函数的主要功能是设置信号传送闹钟,即⽤来设置信号SIGALRM 在经过参数seconds 秒数后发送给⽬前的进程。如果未设置信号SIGALARM 的处理函数,那么alarm()默认处理终⽌进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

        PS:一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。

三. select

#include <sys/select.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval * timeout);

功能:用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds 和exceptfds称为描述词组,是用来回传该描述词的读,写或例外的状况。

         这里就不详细介绍select函数的参数及功能了,大家感兴趣可以自行查阅。这里要实现定时器的话,把第一个参数设置为0,中间三个文件描述符集都设置为NULL,第五个参数为时间结构体,我们主要就是使用参数,把它设置为我们想要定时的频率就好。

        timeout为结构timeval,用来设置select()的等待时间,其结构定义如下:

struct timeval

{

        time_t        tv_sec;

        time_t        tv_usec;
};

#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

void timer_s(unsigned long    s, unsigned long     us)
{
    struct timeval        tv;

    tv.tv_sec = s;
    tv.tv_usec = us;

    select(0, NULL, NULL, NULL, &tv);
}

int main()
{
    while(1)
    {
        printf("hello\n");
        timer_s(3, 0);
    }

    return 0;
}

四. 一些总结

        大家根据自己需求选择,这是在网上扒下来的一张图,原文链接如下:

Linux中的sleep、usleep、nanosleep、poll和select不同的sleep方式https://mp.weixin.qq.com/s?src=11×tamp=1680196399&ver=4438&signature=LzDVJT7uLU7DuxA6qxK8Sm4FqjJw8G347mhB56nkDIb5R2XQsifqz-NFi1nmisdVYxrrRNgLVKIJqjN4koJ59oTtTBWunbaWVMV7u6dNydmBRf-DA9aR6yVNKkbJF*oI&new=1

猜你喜欢

转载自blog.csdn.net/qq_51368339/article/details/129870386