在很多的实际的服务器程序中,针对业务的处理具有超时返回(return if time out)的要求,也就是说不能无限制的处理每一个业务,不能因为一个业务的长时间没有运行完毕就让服务器程序阻塞在处理该业务逻辑的位置而不能继续运行后面的任务,这时,设立timeout机制就成为必须的了,简单地说,就是一旦当业务的处理时间超过了timeout设置的值比如说10秒,那么该业务不再执行而就提前返回,相反,若该业务的处理时间没有超过timeout设置的值,那么该业务执行完毕正常返回,设置timeout的值使得服务器程序在处理该业务的时间长度不长于某个设定值 。
说起来轻松,做起来难呐,到底该怎么样用代码去实现这么一个机制呢?本人研究一阵子,在经过肯定-否定-否定之否定的几个螺旋循环之后,终于修得正果,后来据我一同行哥们说华为的时间锁也是采用我的这个思想,嘿嘿!特发表出来,繁荣网络资源下,下面从两个方面来阐述我的思想:
1,思路:设置一个全局标志量并初始化,这个用来标识具体某个业务是否执行完毕,具体做法是该业务开始执行时修改其值,执行完毕退出前改回原来的值,在程序其他位置就可以观察该全局变量的值是否发生变化来判断该业务逻辑是否执行完毕。另外,必须采用多线程并发执行模式,总不可能等业务逻辑执行完了之后或者开始执行之前开始计时吧,那就太SB了,所以从逻辑上讲,执行业务逻辑和计时应该是同时进行的,就好像跑步比赛,你跑步和教练员计时是同时进行的,要是等教练计时完了你再跑或者等你跑完了教练再开始计时,那就成了国人茶钱饭后的笑料谈资了啊!
2,工欲善其事,必先利其器,得复习一个关键的工具:pthread_cancel这是个好东东诶,可以在一个线程里强奸式结束另外一个线程。
以下是代码实现:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <time.h> //基本上研究清楚了void *print_message_function( void *ptr );void *print_message( void *ptr );void *print(void *ptr);int i=0;
int flag=0;//使用该数的状态切换来表示线程切换pthread_t thread1;pthread_t thread3;
main(){ char *message1 = "Thread 1"; int iret1; iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1); pthread_join( thread1, NULL); printf("整个程序退出!/n") ; exit(0);} void *print_message_function( void *ptr ){ time_t cur1,cur2; cur1=time(NULL); char *message; message = (char *) ptr; printf("%s /n", message); int iret3; flag=11; iret3=pthread_create( &thread3, NULL, print, "my name is 007"); sleep(10);//模拟具体的业务逻辑,假设需要执行10秒钟 flag=0; cur2=time(NULL); printf("函数print_message_function执行时间是%ld秒 /n",cur2-cur1); pthread_join(thread3,NULL); } void *print(void *ptr){ printf("flag=%d ,退出!%s/n",flag,(char *)ptr); sleep(2);//这里的2就是timeout设定值 if(flag) pthread_cancel(thread1);}
输出为:
[root@localhost PosixThread]# mytimerThread 1 flag=11 ,退出!my name is 007整个程序退出!
说明线程1提前退出了,原因在于其执行时间为10秒钟超过了在线程3钟设定的timeout值2秒钟,实际上,程序正是只执行了两秒钟多就退出了(两秒是处理业务逻辑时间,多是其他程序执行时间)
修改程序参数成为如下的情形:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <time.h> //基本上研究清楚了void *print_message_function( void *ptr );void *print_message( void *ptr );void *print(void *ptr);int i=0;
int flag=0;//使用该数的状态切换来表示线程切换pthread_t thread1;pthread_t thread3;
main(){ char *message1 = "Thread 1"; int iret1; iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1); pthread_join( thread1, NULL); printf("整个程序退出!/n") ; exit(0);} void *print_message_function( void *ptr ){ time_t cur1,cur2; cur1=time(NULL); char *message; message = (char *) ptr; printf("%s /n", message); int iret3; flag=11; iret3=pthread_create( &thread3, NULL, print, "my name is 007"); sleep(2);//模拟具体的业务逻辑,假设需要执行10秒钟 flag=0; cur2=time(NULL); printf("函数print_message_function执行时间是%ld秒 /n",cur2-cur1); pthread_join(thread3,NULL); } void *print(void *ptr){ printf("flag=%d ,退出!%s/n",flag,(char *)ptr); sleep(10);//这里的2就是timeout设定值 if(flag) pthread_cancel(thread1);}
[root@localhost PosixThread]# mytimerThread 1 flag=11 ,退出!my name is 007函数print_message_function执行时间是2秒 整个程序退出!
可见设置的timeout为10秒钟竟然比处理业务逻辑的时间好要长,业务逻辑不干了,只需要等自己执行完毕(时长2秒钟)就退出了
以上程序只是简单的模拟了定时器思想,但是毫无疑问,它实现了定时器的两反面逻辑(超时该怎么办吗,没有超时该怎么办),我们可以进一步将它进行封装,并提供对外设置timeout值,业务逻辑入口等对外接口,就可以成为自己的定时器,以后调用起来就很方便了。