时钟信号 SIGALRM ,signal()函数 ,setitimer()函数,pause()函数应用

/** 
 * @file demo5.c
 * @Synopsis  由软件条件产生信号
 * 
 *
 * 时钟信号(SIGALRM)
 * 当内核检测到某种软件发生时也可以通过信号通知进程
 * 
 * 例如闹钟超时产生 该信号;
 * 
 * #include
 * 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
#include
#include
#include
#include

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

你可能感兴趣的:(linux编程)