给Linux C/C++程序设定执行时限
时间管理,是每个现代人的必修课。给一个任务固定的执行时间,是控制整体进度的一种常用方法。
如何让一个运行时间可能比较长的Linux C/C++程序能够有一个执行时限呢?这就是本文要解答的一个问题。
方法一
最直接的做法就是,起一个timer,设定该timer到期发送SIGTERM信号。如果定时器超时后需要做善后工作,那么就给SIGTERM信号写一个信号处理函数;若不需要善后工作,则不用写。
// g++ timer.cpp -lrt#include<ctime>#include<cstdlib>#include<cstdio>#include<cstring>#include<signal.h>#include<unistd.h>voidCreateAndStartTimer(unsignedintwait_seconds){if(wait_seconds==0)return;timer_t timerid;structsigeventsev;structitimerspecits;// Create the timersev.sigev_notify=SIGEV_SIGNAL;sev.sigev_signo=SIGTERM;sev.sigev_value.sival_ptr=&timerid;if(timer_create(CLOCK_MONOTONIC,&sev,&timerid)==-1){fprintf(stderr,"Failed to create timer, will continue running.\n");return;}// Start the timerits.it_value.tv_sec=wait_seconds;its.it_value.tv_nsec=0;its.it_interval.tv_sec=0;its.it_interval.tv_nsec=0;if(timer_settime(timerid,0,&its,NULL)==-1){fprintf(stderr,"Failed to set timer, will continue running.\n");}}intmain(intargc,char*argv[]){unsignedintwait_seconds=0;if(argc!=2){fprintf(stderr,"Usage: %s <time-out-seconds> \n",argv[0]);exit(EXIT_FAILURE);}wait_seconds=atoi(argv[1]);if(wait_seconds>0)CreateAndStartTimer(wait_seconds);while(1){sleep(1);}return0;}以上是最简洁的做法。因为要做的工作就是时间到了杀死本进程,因而也没有什么好多做处理的。
基本上,本文到此就可以结束了。要注意的主要是,timer_create(),timer_settime(),以及sigevent的用法。man一下基本上就比较清楚了。
方法二
在有些情况下,需要捕获实时信号;而在设定实时信号的处理函数时,有可能希望暂时屏蔽实时信号,待设置完再进行处理。这些都是比较常见的需求。
这里以另一个程序来演示实时信号以及屏蔽和去屏蔽信号的做法。
// g++ timer.cpp -lrt#include<ctime>#include<cstdlib>#include<cstdio>#include<cstring>#include<signal.h>#include<unistd.h>#defineerrExit(msg)do{perror(msg);exit(EXIT_FAILURE);}while(0)#defineSIGSIGRTMINtypedefvoid(*signal_handler_t)(int,siginfo_t*,void*);voidsignal_handler(intsigno,siginfo_t*info,void*context){pid_t myself=getpid();kill(myself,SIGTERM);}voidset_signal_handler(intsigno,signal_handler_t handler){structsigactionsigaction_info;memset(&sigaction_info,0,sizeof(sigaction_info));sigset_t sigset_info;sigemptyset(&sigset_info);sigaction_info.sa_handler=NULL;sigaction_info.sa_sigaction=handler;sigaction_info.sa_mask=sigset_info;sigaction_info.sa_flags=SA_SIGINFO;}voidCreateAndStartTimer(unsignedintwait_seconds){if(wait_seconds==0)return;timer_t timerid;structsigeventsev;structitimerspecits;sigset_t mask;set_signal_handler(SIG,signal_handler);// Block timer signal temporarilysigemptyset(&mask);sigaddset(&mask,SIG);if(sigprocmask(SIG_SETMASK,&mask,NULL)==-1){errExit("sigprocmask");}// Create the timersev.sigev_notify=SIGEV_SIGNAL;sev.sigev_signo=SIG;sev.sigev_value.sival_ptr=&timerid;if(timer_create(CLOCK_REALTIME,&sev,&timerid)==-1){fprintf(stderr,"Failed to create timer, will continue running.\n");return;}// Start the timerits.it_value.tv_sec=wait_seconds;its.it_value.tv_nsec=0;its.it_interval.tv_sec=1;its.it_interval.tv_nsec=0;if(timer_settime(timerid,0,&its,NULL)==-1){fprintf(stderr,"Failed to set timer, will continue running.\n");}// Unblock timer signalif(sigprocmask(SIG_UNBLOCK,&mask,NULL)==-1){errExit("sigprocmask");}}intmain(intargc,char*argv[]){unsignedintwait_seconds=0;if(argc!=2){fprintf(stderr,"Usage: %s <time-out-seconds> \n",argv[0]);exit(EXIT_FAILURE);}wait_seconds=atoi(argv[1]);if(wait_seconds>0)CreateAndStartTimer(wait_seconds);while(1){sleep(10);}exit(EXIT_SUCCESS);}方法三
最后,还有一种土办法,可以不用timer. 那就是,再开一个线程,在其中写一个 while (true) 的循环,循环体中 sleep(1). 每次醒来的时候,检查一下时间过去了多久。如果时间已经超过了设定的时限,那么就获得本进程的pid,并且发送 SIGTERM 信号给本进程。
这个代码就不列在这里了,可以参见: ThreadTimeKiller
(END)