/** * @file demo5.c * @Synopsis 由软件条件产生信号 * * * 时钟信号(SIGALRM) * 当内核检测到某种软件发生时也可以通过信号通知进程 * * 例如闹钟超时产生 该信号; * * #include <unistd.h> * unsigned int alarm(unsigned int seconds); * @param unsigned int seconds 接收秒数 * @return unsigned int * 反回值是0,或者是以前设定的闹钟时间还余下的秒数。 * 打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒, * 还想多睡一会儿,于是重新设定闹钟为15分钟之后响,"以前设定的闹钟时间还余 * 下的时间"就是10分钟,如果seconds 值为0,表未闻对酒当歌以前设定的闹钟,函数的 * 返回值仍然是以前设定的闹钟时间还余下的秒数. * 调用alarm 可以设定一个闹钟,也就是告诉内核在seconds 秒之后给当 * 前里程发SIGALRM 信号,该信号的默认处理动作是终止当前进程。 * * @author MrClimb * @version 1.1.0 * @date 2012-05-21 */ #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <signal.h> #include <stdlib.h>
/* *************************************************************** */ /** * @Synopsis alarm()测式5秒后停止该进程 */ /* *************************************************************** */ void test1() { int counter; unsigned int senconds = alarm(5); printf("5秒后停止计数\n"); for(counter=1;;counter++) { printf("counter = %d\n",counter); } printf(" 这一行没有被执行,则被信号终止了。否则。。。"); /*!* * test * Ctrl-C & Ctrl-'\' 当从键盘按下这个个快捷键时立即终止进程,而没有等待 * alarm 去发送信号SIGALRM * 默认情况下当过了5秒之后 alarm 内部将发送信号 SIGALRM 停止进程 * * ? 这里发送终止进程交给内核来终止吗! */ }
/* *************************************************************** */ /** * @Synopsis 程序挂起 * int pause(void); * pause 使调用进程挂起,直到有信号递达。 * 如果信号的处理动作是终止进程,则进程终止,pause 函数没有机会返回, * 如果信号的处理动作是忽略,则进程处于挂起状态,pause 不返回; * 如果信号的处理动作是捕捉,则调用了信号处理函数之后pause 返回 -1,errno 设置为EINTR,所以pause 只有出错的返回值 * 错误码 EINTR 表示" 被信号中断" * * #include <signal.h> * typedef void (*sighandler_t)(int); * sighandler_t signal(int signum,sighandler_t handler); * signal 可以看成 红绿灯; * 也就是说如果信号处理的动作是用户自定义函数,在信号递达时就调用这个函数 * 这称为捕捉信号。 * 这里当传的是signum某一信号,则执行调用 handler 所指向的函数指针 * * ************************** * 1:用户注册了SIGALRM 信号的处理函数 sighandler 。 * 2:当前正在执行main函数,这时发生中断或异常切换到内核态。 * 3:在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGALRM 递达 * 4:内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler 函数,sighandler 和main函数使用不 * 同的堆栈空间,它们之间不存在调用和被调用的关糸,是两个独立的控制流程 * 5:sighandler 函数返回后自动执行特殊的糸统调用sigreturn 再次进入内核态。 * 6:如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。 * * ************************** * ?这里捕捉信号号 signal 后它不会作终止当前进程吗!,而test1则会终止当前进程呢。 */ /* *************************************************************** */ void test2() { // 定义该函数 void wakeup(int); printf("about to sleep for 4 seconds\n"); signal(SIGALRM,wakeup);// 这里是在 4秒后捕捉到 alarm 产生的 SIGALRM 信号 alarm(4); // 当前进程挂起 pause(); printf("Morning so soon?(这里被执行了,说明信号没有终止程序)\n"); } void wakeup(int isignum) { printf("起床啦!时间到了。(捕捉到信号了。。)\n"); } /* *************************************************************** */ /** * @Synopsis 获得一个精确的定时。。 * 操作糸统提供三种时间: * 使用命令: time ./a.out 生成三个时间 * real/user/sys 三个时间 * 用户时间、用户与内核切换时间。。 * * int setitimer(int which,const struct itimerval *new_value,struct itimerval *old_value) * 将new_value 指向的结构体设为计时器的当前值,如果old_value不是NULL,将返回计时器原有值。 * * @param int which:间歇计时器类型,有三种选择 * ITIMER_REAL // 数值为0,计时器的值实时递减,发送的信号SIGALRM * 类似于alarm()当某个计数时间完了后就产生一个这样的信号 * ITIMER_VIRTUAL // 数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM * 进程在执行,进程在用户空间执行,计时用户空间进程时间,用完之后产生一个信号SIGVTALRM * ITIMER_PROF // 数值为2,进程和糸统执行都递减计时器的值,发送的信号是SIGPROF. * 用户时间加上切换时间,一个进程要三个时间,那么十个进程,就得几百个时钟了, * 那么怎么处理呢。物理时钟只有一个,这里物理时钟进行递减,那么其它进程时钟也作相应自减, * 直到其它进程减到0为止,则发送信号。 * * struct itimerval{ * struct timeval it_interval;// next value;计时器重启的间歇值 * struct timeval it_value;// current value;计时器安装后首先启动的初始值 * } * struct timeval{ * long tv_sec;// seconds * long tv_usec;// microseconds (1/1000000) * } * @return success is returned value zero * failure is returned value -1 errno will be set 某个值 * EFAULT : new_value or old_value * EINVAL : 其值不是 ITIMER_REAL,ITIMER_VIRTUAL OR ITIMER_PROF之一 * */ /* *************************************************************** */ int set_ticker(int n_msecs) { // 这里用两个时间,一个是时间,一个是时间间隔。 struct itimerval new_timeset; long n_sec;// 秒 long n_usecs;// 微秒 n_sec = n_msecs/1000; n_usecs = (n_msecs % 1000) * 1000L;
new_timeset.it_interval.tv_sec = n_sec; new_timeset.it_interval.tv_usec = n_usecs;
new_timeset.it_value.tv_sec = n_sec; new_timeset.it_value.tv_usec = n_usecs;
return setitimer(ITIMER_REAL,&new_timeset,NULL); } void countdown(int signum) { static int num = 10; printf("%d..",num--); fflush(stdout);// 强制输出缓冲区 if(num < 0) { printf("DONE!\n"); exit(0); } } void test3() { void countdown(int); signal(SIGALRM,countdown);// 当捕捉到信号 SIGALRM 将执行 countdown 函数 下面 while 函数仍旧不断的循环。。 if(set_ticker(1000) == -1) { perror("set_ticker"); }else { while(1) { pause();// 进程 永远 挂起 } } } int main(int argc, char **argv) { #if 0 test1(); #endif #if 0 test2(); #endif #if 1 test3(); #endif
return 0; }