1.linux下调用系统函数alarm(),setitimer(),sleep(),usleep()(实现微妙定时),linux
2.单纯c语言实现gettimeofday()(微妙定时),time(),windows
3.windows可用Sleep()实现微秒级定时函数
1.alarm()进程
#include <unistd.h>
unsigned int alarm(unsigned int seconds);字符串
函数返回值get
成功:若是调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,不然返回0。不阻塞!!!string
出错:-1it
做用: 调用 alarm 函数即设定一个闹钟,也就是告诉内核在 seconds 秒以后给当前进程发 SIGALRM 信号,默认处理动做是终止当前进程。闹钟返io
回值是 0 或者是之前设定的闹钟时间还余下的秒数。若是 seconds 值为 0,表示取消之前设定的闹钟,函数的返回值仍然
是之前设定的闹钟时间还余下的秒数。
例ast
------ 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.c1. #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秒到了就给你输出一个字符串。因此,若是你只作通常的定时,到了时间去执行一个任务,这种方法是最简单的。