龙空技术网

定时器全场景全方位学习

Linux天神 53

前言:

而今大家对“c语言的定时器函数是什么”大约比较珍视,大家都需要分析一些“c语言的定时器函数是什么”的相关文章。那么小编也在网上收集了一些关于“c语言的定时器函数是什么””的相关内容,希望看官们能喜欢,各位老铁们一起来学习一下吧!

1. C实现定时器的几种方式linux下调用系统函数alarm(),setitimer(),sleep(),usleep()(实现微妙定时),单纯c语言实现gettimeofday()(微妙定时),time(),windows可用Sleep()实现微秒级定时1.1 alarm()

头文件:

#include <unistd.h>

函数原型:

unsigned int alarm(unsigned int seconds);

函数返回值:

成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的 剩余时间,            否则返回0。不阻塞!!出错:-1

作用:

调用 alarm 函数即设定一个闹钟,也就是告诉内核在 seconds 秒之后给当前进程 发 SIGALRM 信号,  默认处理动作是终止当前进程。闹钟返回值是 0 或者是以前设定的闹 钟时间还余下的秒数。如  果 seconds 值为 0,表示取消以前设定的闹钟,函数的返回值仍然 是以前设定的闹钟时间还余下的  秒数。

示例:

#include <unistd.h>#include <stdio.h> int main(void){    int counter;    alarm(1);    for(counter=0; 1; counter++)        printf("counter=%d ", counter);    return 0;}

这个程序的作用是 1秒钟之内不停地数数, 1秒钟到了就被 SIGALRM 信号终止。

1.1.1配合pause函数实现sleep函数!

头文件:

#include <unistd.h>

函数原型:

int pause(void)

函数返回值:

如果信号的处理动作是忽略,则进程继续处于挂起状态,pause 不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后 pause 返回-1,errno 设置为 EINTR,所以pause只有出错的返回值。错误码 EINTR表示“被信号中断”。

作用:

pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;

下面我们用 alarm 和 pause 实现 sleep(3)函数。

示例:

#include <unistd.h>#include <signal.h>#include <stdio.h> void sig_alrm(int signo){    /* nothing to do */} unsigned int mysleep(unsigned int nsecs){    struct sigaction newact, oldact;    unsigned int unslept;    newact.sa_handler = sig_alrm;    sigemptyset(&newact.sa_mask);    newact.sa_flags = 0;    sigaction(SIGALRM, &newact, &oldact);    alarm(nsecs);    pause();    unslept = alarm(0);    sigaction(SIGALRM, &oldact, NULL);    return unslept;} int main(void){    while(1){        mysleep(2);        printf("Two seconds passed\n");    }    return 0;}
main 函数调用 mysleep 函数,后者调用 sigaction 注册了 SIGALRM 信号的处理函数 sig_alrm。调用 alarm(nsecs)设定闹钟。调用 pause 等待,内核切换到别的进程运行。nsecs 秒之后,闹钟超时,内核发 SIGALRM 给这个进程。从内核态返回这个进程的用户态之前处理未决信号,发现有 SIGALRM 信号,其处理函数是 sig_alrm。切换到用户态执行 sig_alrm 函数,进入 sig_alrm 函数时 SIGALRM 信号被自动屏蔽,从 sig_alrm 函数返回时 SIGALRM 信号自动解除屏蔽。然后自动执行系统调用 sigreturn 再次进入内核,再返回用户态继续执行进程的主控制流程(main 函数调用的 mysleep 函数)。pause 函数返回-1,然后调用 alarm(0)取消闹钟,调用 sigaction 恢复SIGALRM 信号以前的处理动作。

学习更多关于定时器内容请私信:定时器全场景全方位学习,

1.2 setitimer()

常用到的函数:

#include <sys/time.h>int getitimer (int which, struct itimerval* value);int setitimer (int which, struct itimerval* newvalue, struct itimerval* oldvalue);

which有三种状态:

ITIMER_REAL: 对指定时间值,按自然时间计数, 时间到发出SIGALRM信号.ITIMER_VIRTUAL: 对指定时间值, 当只在用户态时(进程执行的时候)计数, 时间到发出SIGVTALRM信号.ITIMER_PROF: 对指定时间值, 用户态或内核态(进程执行与系统为进程调度)都计数, 时间到, 发出SIGPROF信号, 与ITIMER_VIRTVAL联合, 常用来计算系统内核时间和用户时间.

struct timeval{    long tv_sec; /* 秒 */    long tv_usec; /* 微秒 */}; struct itimerval{    struct timeval it_interval;  /* 时间间隔 *///循环定时时间    struct timeval it_value;    /* 当前时间计数 *///第一次计时时间};

it_interval用来指定每隔多长时间执行任务, it_value用来保存当前时间离执行任务还有多长时间. 比如说, 你指定it_interval为2秒(微秒为0), 开始的时候我们把it_value的时间也设定为2秒(微秒为0), 当过了一秒, it_value就减少一个为1, 再过1秒, it_value又减少1, 变为0, 这个时候发出信号(告诉用户时间到了, 可以执行任务了), 并且系统自动把it_value的值重置为it_interval的值, 即2秒, 再重新计数.

示例:

#include <sys/time.h>#include <stdio.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <stdlib.h> static char msg[] = "time is running out.\n";static int len; /* time's up */void prompt_info(int signo){    write (STDERR_FILENO, msg, len);}void init_sigaction(void){    struct sigaction tact;    tact.sa_handler = prompt_info;    tact.sa_flags = 0;    sigemptyset (&tact.sa_mask);    sigaction (SIGALRM, &tact, NULL);}void init_time(){    struct itimerval value;    value.it_value.tv_sec = 2;    value.it_value.tv_usec = 0;    value.it_interval = value.it_value;    /* set ITIMER_REAL */    setitimer (ITIMER_REAL, &value, NULL);}int main(int argc, char** argv){    len = strlen (msg);    init_sigaction ();    init_time ();    while (1);    exit (0);}

该程序的ITMER_REAL定时器,每隔2秒钟都会发送一个SIGALRM信号,当主函数接收到了这个信号之后,调用信号处理函数prompt_info在标准错误上输出time is running out这个字符串。

对于ITIMER_VIRTUAL和ITIMER_PROF的使用方法类似,当你在setitimer里面设置的定时器为ITIMER_VIRTUAL的时候,你把sigaction里面的SIGALRM改为SIGVTALARM, 同理,ITIMER_PROF对应SIGPROF。

不过,你可能会注意到,当你用ITIMER_VIRTUAL和ITIMER_PROF的时候,你拿一个秒表,你会发现程序输出字符串的时间间隔会不止2秒,甚至5-6秒才会输出一个,那是因为cpu在用户与内核切换之间也会浪费时间,这段时间是不计入在指定时间范围之内的。

1.3 time()或gettimeofday()利用时间差来计算

#include <signal.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <time.h> //包含time()函数#include <sys/time.h>//包含gettimeofday()函数 static char msg[] = "All just want to be better you.\n";int len;static time_t lasttime; void show_msg(int signo){    write(STDERR_FILENO, msg, len);} int main() {     struct sigaction act;     union sigval tsval;      act.sa_handler = show_msg;     act.sa_flags = 0;     sigemptyset(&act.sa_mask);     sigaction(50, &act, NULL);     len = strlen(msg);     time(&lasttime);     while (1)     {         time_tnowtime;         /*获取当前时间*/         time(&nowtime);         /*和上一次的时间做比较,如果大于等于2秒,则立刻发送信号*/         if (nowtime - lasttime >= 2)         {             /*向主进程发送信号,实际上是自己给自己发信号*/             sigqueue(getpid(), 50, tsval);             lasttime = nowtime;         }            }     return 0; }

如果你想更精确的计算时间差,你可以把 time 函数换成gettimeofday,这个可以精确到微妙。

上面介绍的几种定时方法各有千秋,在计时效率上、方法上和时间的精确度上也各有不同,采用哪种方法,就看你程序的需要。

1.4 sleep实现方法

下面我们来看看用sleep以及usleep怎么实现定时执行任务。

示例

 #include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h>  static char msg[] = "All just want to be better you.\n";int len;void show_msg(int signo){     write(STDERR_FILENO, msg, len);} int main(){    struct sigaction act;    union sigval tsval;    act.sa_handler = show_msg;    act.sa_flags = 0;    sigemptyset(&act.sa_mask);    sigaction(50, &act, NULL);    len = strlen(msg);    while( 1 )    {        sleep(2); /*睡眠2秒*/        /*向主进程发送信号,实际上是自己给自己发信号*/        sigqueue(getpid(), 50, tsval);    }    return 0;}
1.5 clock()
#include <stdio.h>#include <time.h>#include <conio.h> #ifndef CLOCKS_PER_SEC#define CLOCKS_PER_SEC 1000#endif int main( void ){    clock_t start;    long count = 1;    start = clock();    while(1)    {        if((clock() - start) == CLOCKS_PER_SEC)        {            printf("%ld\n",count++);            start = clock();            //break;        }    }    getch();}

代码抽象出一个定时器函数 void timer(long time)

void timer(long time) {    clock_t start;    long count = 1;    start = clock();    while(1)    {        if((clock() - start) != (time*CLOCKS_PER_SEC))        {            //时间没有到,啥也不做,空循环        }else {            //时间到了退出循环            // printf("%s","hello");            break;        }     }}

完整代码

#include <stdio.h>#include <time.h>#include <conio.h> #ifndef CLOCKS_PER_SEC#define CLOCKS_PER_SEC 1000#endif/*** time 的单位为s*/void timer(long time){    clock_t start;    long count = 1;    start = clock();    while(1)    {        if((clock() - start) != (time*CLOCKS_PER_SEC))        {            //时间没有到,啥也不做,空循环        }else {            //时间到了退出循环            // printf("%s","hello");            break;        }    }}int main(void){    for(int i=0;i<10;i++){        timer(1);        printf("%d\n",i);    }    getch();}

标签: #c语言的定时器函数是什么 #定时器应用场景

上一篇华中农业大学通报:启动调查

下一篇没有了