c实现的几种定时器

1.linux下调用系统函数alarm(),setitimer(),sleep(),usleep()(实现微妙定时),

2.单纯c语言实现gettimeofday()(微妙定时),time(),

3.windows可用Sleep()实现微秒级定时

1.alarm()

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

函数返回值

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

出错:-1

作用:  调用 alarm 函数即设定一个闹钟,也就是告诉内核在 seconds 秒之后给当前进程发 SIGALRM 信号,默认处理动作是终止当前进程。闹钟返

回值是 0 或者是以前设定的闹钟时间还余下的秒数。如果 seconds 值为 0,表示取消以前设定的闹钟,函数的返回值仍然
是以前设定的闹钟时间还余下的秒数。

------ alarm
#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 配合pause函数实现sleep函数!

#include <unistd.h>
int pause(void);
pause 函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause 函数没有机会返回;如果信号的处理动作是忽略,则
进程继续处于挂起状态,pause 不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后 pause 返回-1,errno 设置为 EINTR,所以 pause 只有出错
的返回值(想想以前还学过什么函数只有出错返回值?)。错误码 EINTR 表示“被信号中断”。
下面我们用 alarm 和 pause 实现 sleep(3)函数,称为 mysleep。
mysleep
#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;
}
    1. main 函数调用 mysleep 函数,后者调用 sigaction 注册了 SIGALRM 信号        的处理函数 sig_alrm。
    2. 调用 alarm(nsecs)设定闹钟。
    3. 调用 pause 等待,内核切换到别的进程运行。
    4. nsecs 秒之后,闹钟超时,内核发 SIGALRM 给这个进程。
    5. 从内核态返回这个进程的用户态之前处理未决信号,发现有 SIGALRM 信号,其处理函数是 sig_alrm。
    6. 切换到用户态执行 sig_alrm 函数,进入 sig_alrm 函数时 SIGALRM 信号被自动屏蔽,从 sig_alrm 函数返回时 SIGALRM 信号自动解除屏蔽。然后
        自动执行系统调用 sigreturn 再次进入内核,再返回用户态继续执行进程的主控制流程(main 函数调用的 mysleep 函数)。
    7. pause 函数返回-1,然后调用 alarm(0)取消闹钟,调用 sigaction 恢复SIGALRM 信号以前的处理动作。

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在用户与内核切换之间也会浪费时间,这段时间是不计入在指定时间范围之内的。

3.time()或gettimeofday()利用时间差来计算--------------------------------------------------------------------------------------------------------------------------

1. #include <signal.h> 
2. #include <unistd.h> 
3. #include <string.h> 
4. #include <stdio.h> 
5. #include <time.h> //包含time()函数

6.#include <sys/time.h>//包含gettimeofday()函数

7. staticchar msg[] = "I received a msg.\n";

8. int len; 
9. static time_t lasttime; 
10. void show_msg(int signo) 
11. { 
12.     write(STDERR_FILENO, msg, len); 
13. } 
14. intmain() 
15. { 
16.     structsigaction act; 
17.     unionsigval tsval; 
18. 
19.     act.sa_handler = show_msg; 
20.     act.sa_flags = 0; 
21.     sigemptyset(&act.sa_mask); 
22.     sigaction(50, &act, NULL); 
23. 
24.     len = strlen(msg); 
25.     time(&lasttime); 
26.     while( 1 ) 
27.     { 
28.         time_tnowtime; 
29.         /*获取当前时间*/ 
30.         time(&nowtime); 
31.         /*和上一次的时间做比较,如果大于等于2秒,则立刻发送信号*/ 
32.         if(nowtime - lasttime >= 2) 
33.         { 
34.             /*向主进程发送信号,实际上是自己给自己发信号*/ 
35.             sigqueue(getpid(), 50, tsval); 
36.             lasttime = nowtime; 
37.         }        
38.     } 
39.     return0; 
40. }

如果你想更精确的计算时间差,你可以把 time 函数换成gettimeofday,这个可以精确到微妙。
上面介绍的几种定时方法各有千秋,在计时效率上、方法上和时间的精确度上也各有不同,采用哪种方法,就看你程序的需要

4 sleep实现方法-------------------------------------------------------------------------------------------------------------------------------------------------------------

下面我们来看看用sleep以及usleep怎么实现定时执行任务。
下载: timer2.c
1. #include <signal.h> 
2. #include <unistd.h> 
3. #include <string.h> 
4. #include <stdio.h> 
5. 
6. staticchar msg[] = "I received a msg.\n"; 
7. int len; 
8. void show_msg(int signo) 
9. { 
10.     write(STDERR_FILENO, msg, len); 
11. } 
12. intmain() 
13. { 
14.     structsigaction act; 
15.     unionsigval tsval; 
16. 
17.     act.sa_handler = show_msg; 
18.     act.sa_flags = 0; 
19.     sigemptyset(&act.sa_mask); 
20.     sigaction(50, &act, NULL); 
21. 
22.     len = strlen(msg); 
23.     while( 1 ) 
24.     { 
25.         sleep(2); /*睡眠2秒*/ 
26.         /*向主进程发送信号,实际上是自己给自己发信号*/ 
27.         sigqueue(getpid(), 50, tsval); 
28.     } 
29.     return0; 
30. }
看到了吧,这个要比上面的简单多了,而且你用秒表测一下,时间很准,指定2秒到了就给你输出一个字符串。所以,如果你只做一般的定时,到了时间去执行一个任务,这种方法是最简单的。

时间: 2024-08-26 19:54:40

c实现的几种定时器的相关文章

TCP协议中的四种定时器

TCP四种定时器 重传计时器.坚持计时器.保活计时器.时间等待计时器 重传计时器: 在TCP发送报文时创建,用来确认报文是否成功发送,超过预定时间,则重新发送,设置重传计时器之后,通常有两种情况: 1.在计时器截止时间到达之前收到了对以发送报文的确认信号,则撤销此计数器: 2.计时器时间到达仍未收到确认信号,则重新发送该报文,并将计时器复位. 坚持计时器: 这种计时器通常是和窗口大小有关的. 先考虑这样一种场景:发送端由于发送速度太快,接收端的窗口大小为零,这是接收段就会发送信号告诉发送端,我现

Qt分析:Qt中的两种定时器(可是QObject为什么要提高定时器呢,没必要啊。。。)

Qt有两种定时器,一种是QObject类的定时器,另一种是QTimer类的定时器. (1)QObject类的定时器 QObject类提供了一个基本的定时器,通过函数startTimer()来启动,通过killTimer()来结束,通过QTimerEvent来处理定时器事件. int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer); void killTimer(int id); void QObject::t

javascript两种定时器的使用及其清除

<!--示例代码如下:--><!DOCTYPE html> <html> <body> <p>A script on this page starts this clock:</p> <p id="demo"></p> <input type="button" value="停止" onclick="abc()"/> &

cocos2dx三种定时器的使用

 cocos2dx三种定时器的使用以及停止schedule,scheduleUpdate,scheduleOnce 今天白白跟大家分享一下cocos2dx中定时器的使用方法. 首先,什么是定时器呢?或许你有时候会想让某个函数不断的去执行,或许只是执行一次,获取你想让他每隔几秒执行一次,ok,这些都可以统统交给定时器来解决. cocos2dx中有三种定时器:schedule,scheduleUpdate,scheduleOnce.了解其功能便会发现定时器真是太方便了,废话不多说,我们逐一学习一

cocos2dx三种定时器使用

 cocos2dx三种定时器的使用以及停止schedule.scheduleUpdate.scheduleOnce 今天白白跟大家分享一下cocos2dx中定时器的用法. 首先,什么是定时器呢?也许你有时候会想让某个函数不断的去运行.也许仅仅是运行一次,获取你想让他每隔几秒运行一次.ok.这些都能够统统交给定时器来解决. cocos2dx中有三种定时器:schedule,scheduleUpdate.scheduleOnce.了解其功能便会发现定时器真是太方便了,废话不多说,我们逐一学习一下

Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLink : NSObject { @private void *_impl; //指针 } + (CADisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel;//唯一一个初始化方法 - (void)addToRunLoop:(NS

C#三种定时器的实现

·关于C#中timer类 在C#里关于定时器类就有3个 1.定义在System.Windows.Forms里 2.定义在System.Threading.Timer类里 3.定义在System.Timers.Timer类里 System.Windows.Forms.Timer是应用于WinForm中的,它是通过Windows消息机制实现的,类似于VB或Delphi中 的Timer控件,内部使用API SetTimer实现的.它的主要缺点是计时不精确,而且必须有消息循环,Console Appli

《网络协议》TCP 四种定时器

TCP 是提供可靠的传输层,它使用的方法之一就是确认从另一端收到的数据.但是数据和确认都可能会丢失.TCP 通过在发送时设置一个定时器来解决这个问题.如果当定时器溢出时还没收到确认,它就会重传该数据.关键在于超时和重传策略,即怎样决定超时的时间间隔和如何确定重传的频率. 对于每个连接,TCP 管理着四个不同的定时器:重传定时器.坚持定时器.保活定时器 以及  2MSL 定时器. 重传定时器 为了防止丢失数据报文段或确认报文段,当 TCP 发送报文段时,启动了特定报文段的重传计时器,若在计时器超时

08第二种定时器_封装动画函数_轮播图_offset系列

前面复习: 下面会说第二种定时器. 第二种定时器: 第一种的定时器回顾: 另一个定时器 setTimeout() 它是一个一次性的定时器: 因为,代码是从上往下执行的,btn 还没有生成,所以getElementById("btn").onclick = 肯定是会报错的. 它是一次性的定时器,如果没有取消的话,它会一直占着空间,所以一般都要写按钮btn 去取消timeId  . 1 <!DOCTYPE> 2 <html lang="en">

关于js中两种定时器的设置及清除

1.JS中的定时器有两种: window.setTimeout([function],[interval]) 设置一个定时器,并且设定了一个等待的时间[interval],当到达时间后,执行对应的方法[function],当方法执行完成定时器停止(但是定时器还在,只不过没用了); window.setInterval([function],[interval]) 设置一个定时器,并且设定了一个等待的时间[interval],当到达时间后,执行对应的方法[function],当方法执行完成,定时器