/**
* @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;
}