9--Linux学习----信号

来源:互联网 发布:stc12c5a32s2数据手册 编辑:程序博客网 时间:2024/05/21 18:43

---------------------------------信号------------------------------------------

                             

   1. 信号的作用

     通知其他进程相应。进程之间一种通信机制

    信号处理函数:

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

小小案例(引出什么是信号)

//  signaldeal.c#include <unistd.h>#include <stdio.h>#include <signal.h>void deal(int s){printf("信号发生!\n");}main(){signal(SIGINT,deal);while(1){printf("进程执行!\n");sleep(1);}}


常见处理信号命令:

------------------------------------------------

$ kill  -s  信号  进程ID ----信号: 数字1-31  34-64

$kill -l  -- 查看所有信号

------------------------------------------------

案例: 使用程序发送信号

    int kill(pid pid, int s)

          进程ID:

                >0 :  发送信号到指定的进程

               =0 : 发送信号到该进程所在进程组的所有进程

               =-1 : 发送给所有进程,除init外

               <0 : 发送给指定的进程组。

  2.信号的发送 与 安装

      signal

      kill

  3.信号的应用

     3.1 延时器 timeout

         SIGALRM

         信号发出函数: alarm

         #include <unistd.h>

          unsigned int alarm(unsigned int seconds);

   说明: alarm函数在sec秒之后发送一个SIGALRM信号

     3.2 定时器(有周期性,反复发送)

      #include <sys/time.h>
       int setitimer(int which,  // 3种计时方式ITIMER_REAL(真实时间),ITIMER_VIRTUAL,ITIMER_PROF

                     const struct itimerval *new_value, // 定时器
                     struct itimerval *old_value); // 返回原来设置的定时器,如果为NULL,不返回


          struct itimerval {
               struct timeval it_interval; /* next value */  间隔时间
               struct timeval it_value;    /* current value */ 延时时间
           };

           struct timeval {
               time_t      tv_sec;         /* seconds */
               suseconds_t tv_usec;        /* microseconds */
           };

案例1: 指定时间执行

#include <stdio.h>#include <signal.h>void deal(int s){printf("起床!\n");}main(){signal(SIGALRM,deal);alarm(5);while(1){  // ....}}

案例2: (5秒后,每隔1秒打印)

// alarm2.c#include <stdio.h>#include <signal.h>#include <sys/time.h>void deal(int s){   // printf("\7");   fprintf( stdout, "\7" );printf("起床\n");}main(){struct itimerval v = {0};signal(SIGALRM,deal);v.it_value.tv_sec = 5;    // 延时时间v.it_interval.tv_sec  = 1 ;///间隔时间setitimer(ITIMER_REAL,&v,0);while(1){//...}}

   信号的应用:

    系统与应用程序之间

    应用与应用程序之间

    父子进程之间

案例: 使用单进程 + 信号中断

    使用定时器信号(不是进程),实现多任务。


/// demo1.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <curses.h>#include <math.h>#include <sys/time.h>#include <string.h>#include <time.h>WINDOW *wtime, *wnumb;int num,i;void showtime(int s){time_t tt;struct tm *t;if(s == SIGALRM){tt = time(0);//time(&tt);t = localtime(&tt);mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);refresh();//wrefresh(wtime);//wrefresh(wnumb); }}main(){    struct itimerval val;initscr();curs_set(0); /// 隐藏光标signal(SIGALRM,showtime);/// 绑定一个信号,让时间显示bzero(&val,sizeof(struct itimerval));val.it_value.tv_sec=0;  ///设置为立即显示延时时间,可以试试,这句不能少,不然滞后显示val.it_value.tv_usec = 1;// 间隔时间val.it_interval.tv_sec = 1;wnumb = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);  //高度3,宽度11wtime = derwin(stdscr,3,10,0,(COLS-10)/2);box(wnumb,0,0);  // 加上边框box(wtime,0,0);setitimer(ITIMER_REAL,&val,0);  //不可少,启动定时器while(1){num = 0;for(i=0; i<7; ++i){num = num*10 +rand()%10;}mvwprintw(wnumb,1,2,"%07d",num);refresh();wrefresh(wnumb);sleep(1);wrefresh(wtime);usleep(10000);}endwin();}



案例2 : 多进程 + 信号 的应用 

    实现父子进程之间的通信

    sleep  与 pause 函数被信号影响后,它们将不会继续执行。

    随机显示7位随机属,当按下空格后,随机数停止显示

// demo2.c #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <curses.h>#include <math.h>#include <sys/time.h>#include <string.h>WINDOW *w;int num;int istop  =0;void handle(int s){if(s == SIGUSR1){if(istop == 0) istop = 1;else istop = 0;}}main(){initscr();curs_set(0); // 隐藏光标noecho(); /// 禁止输入显示/// 创建子窗体w = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);keypad(stdscr,TRUE); // z支持功能键keypad(w,TRUE);// 给窗体加边框box(w,0,0);refresh();wrefresh(w); if( fork() ) /// 父进程{    signal(SIGUSR1,handle); // handle函数绑定到信号上while(1){if(istop == 1){pause();  /// 进程挂起}num = 0;num = rand()%10000000;mvwprintw(w,1,2,"%07d",num);refresh();wrefresh(w);usleep(100000);}}else  //子进程中处理按键 {while(1){    int ch;ch = getch();if(ch == 32)  // 32指的是空格键{kill(getppid(),SIGUSR1);}}}endwin();}

   4.信号的可靠与不可靠 

      信号有丢失现象。

      分为:可靠信号 与 不可靠信号

      早期: 信号1-31   31个信号,不可靠(与系统有关)

      后期: 信号34-64  可靠信号(用户有关)

  5.信号的操作

     信号导致的问题:

    1.信号的屏蔽

      #include <signal.h>

       int sigprocmask(int how,
  // 操作方式

          SIG_BLOCK ----把参数set中的信号添加到信号屏蔽字中

               SIG_SETMASK --- 把信号屏蔽字设置为参数set中的信号

               SIG_UNBLOCK ---  从信号屏蔽字中删除参数set中的信号

   const sigset_t *set,  // 操作信号的集合

   sigset_t *oldset);  // 返回原来操作的信号集合

   编程步骤:

    1.声明信号集合

      sigset_t  sigs;

    2.加入屏蔽信号

      一组信号集合维护函数

      2.1 清空集合  int sigemptyset(sigset_t *set);

      2.2 添加信号到集合 int sigaddset(sigset_t *set, int signum);

      2.3 从集合中删除信号 int sigdelset(sigset_t *set, int signum);

      2.4 添加所有信号到集合  int sigfillset(sigset_t *set); 

      2.5 判定信号是否在集合 int sigismember(const sigset_t *set, int signum);

    3.屏蔽信号

    4.解除屏蔽

案例: (花费10秒钟计算1-10之间的和,外界中断信号不会影响程序的执行)


// mask.c#include <stdio.h>#include <signal.h>main(){int sum = 0;int i;// 1sigset_t sigs;//2sigemptyset(&sigs); // 清空信号集合sigaddset(&sigs,SIGINT); // 添加SIGINT 这个信号到信号集合//3 屏蔽SIGINT(Ctrl+c) 这个信号sigprocmask(SIG_BLOCK,&sigs,0); for(i=0; i<=10; ++i){sum += i;sleep(1);}printf("sum = %d\n",sum);//4.sigprocmask(SIG_UNBLOCK,&sigs,0);// 从信号屏蔽子中删除参数set中的信号printf("Over!\n"); // 这个有可能被外界信号干扰}

  2.信号屏蔽的切换

          int sigsuspend(const sigset_t *mask);-------------------目前还没有理解这个函数,


   sigsuspend 是阻塞函数,对参数信号屏蔽。

  3.查询被屏蔽的信号

          int sigpending(sigset_t *set);











0 0
原创粉丝点击