信号(1)

以前在看APUE的时候,就没有看信号这一章,如今APUE的书还给图书馆了,换了一本linux C程序设计,这本书虽然比APUE还普遍,但是和APUE比起来仍是有差距,中国人老想着用文字去说明问题,不用例子去说明,并且例子不能运行的,例子和例子之间千丝万缕的关系的 仍是有不少的。总之,我以为Linux C程序设计还有不少能改进的地方,至少风格,示例是能够好好改进一下的
如今把信号简单补充一下:
[root@server myprogram]# kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     17) SIGCHLD
18) SIGCONT     19) SIGSTOP     20) SIGTSTP     21) SIGTTIN
22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO
30) SIGPWR      31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1
36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4  39) SIGRTMIN+5
40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8  43) SIGRTMIN+9
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6  59) SIGRTMAX-5
60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2  63) SIGRTMAX-1
64) SIGRTMAX
可见,我这里有64个信号,而且从1开始排序
那么对于信号的处理是怎么一回事情呢?其实,进程中对于信号的处理是异步的,无论进程在干什么,那么是个死循环,也会去响应信号,去作信号处理函数
譬如:
int main()
{
     while(1) ;
     return 0;
}
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test
当咱们按下Ctrl+c的时候,进程终止,这是进程响应SIGINT信号的结果
为了更明白一点,咱们这样作
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test &
[1] 1790
[root@server myprogram]# kill -SIGSEGV 1790
[root@server myprogram]# 
[1]+  Segmentation fault      ./test
[root@server myprogram]# 
想向进程发送SIGSEGV信号,用kill -SIGSEGV 1790的命令
为何要enter两次它才输出segmentation fault呢?由于在进程1790结束以前已经已经回到了shell提示符,等待用户输入下一条命令,shell不但愿段错误的信息和用户的输入交错在一块儿,因此等待用户输入命令之后才显示进程发生了段错误,而且生成一个core文件。
下面看一个示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void sigusr_handler(int signo)//用户信号1和用户信号2的处理函数
{
  switch(signo)
  {
     case SIGUSR1:
      printf( "Parent : catch SIGUSR1\n");
      break;
     case SIGUSR2:
      printf( "Child : catch SIGUSR2\n");
      break;
    default:
      printf( "should not be here\n");
      break;
  }
  return ;
}

int main(void)
{
  pid_t ppid, cpid;

   if(signal(SIGUSR1, sigusr_handler) == SIG_ERR)
  {
    perror( "can't set handler for SIGUSR1");
     exit(1);
  }

   if(signal(SIGUSR2, sigusr_handler) == SIG_ERR)
  {
    perror( "can't set handler for SIGUSR2");
     exit(1);
  }

  ppid = getpid();//后去进程ID

   if((cpid = fork()) <0)//fork建立子进程
  {
    perror( "fail to fork");
     exit(1);
  }
   else if(cpid == 0)//在子进程中
  {
    printf( "child\n");
     if(kill(ppid, SIGUSR1) == -1)//往父进程发SIGUSR1信号
    {
      perror( "fail to send signal");
       exit(1);
     }
      while(1)     ;
  }
   else//在父进程中
  {
    //printf( "parent\n");
    sleep(1);
     if(kill(cpid, SIGUSR2) == -1)//往子进程中发SIGUSR2信号
    {
      perror( "fail to send signal");
       exit(1);
    }

    printf( "kill child\n");
    
     if(kill(cpid, SIGKILL) == -1)//kill子进程
    {
      perror( "fail to send signal");
       exit(1);
    }

     if(wait( NULL) == -1)//等待一个子进程退出
    {
      perror( "fail to wait");
       exit(1);
    }
  }

  return 0;
}
信号是有限的,咱们不能随便定义本身的信号,有两个信号是留给用户本身用的,分别是SIGUSR1,SIGUSR2。
这个例子实现了发送信号,信号处理函数的应用
程序执行结果以下:
[root@server myprogram]# gcc -o test test.c
[root@server myprogram]# ./test
child
Parent : catch SIGUSR1
kill child
Child : catch SIGUSR2
有趣的是,若是我只是掉printf("child");这一句,那么Child : catch SIGUSR2这一句也打印不出来,等哪位知道缘由的仁兄指教。。。
相关文章
相关标签/搜索