APUE 学习笔记(七) 信号

1.信号是软件中断,提供一种异步处理事件的方法

很多事件产生信号:
(1)用户按下某些中断键,如 Ctrl + C键产生 SIGINT信号
(2)硬件异常产生信号,比如 除数为0, 无效的内存引用 
(3)进程调用kill函数可将信号发送给另一个进程
 
处理信号的三种方式:
(1) 忽略此信号。大多数信号都采用这种方式处理,但是 SIGKILL和SIGSTOP决不能忽略
(2)捕捉信号。发生某种信号时,调用一个信号处理函数。SIGKILL和SIGSTOP信号不能被捕捉
(3)执行系统默认动作。大多数是终止进程
 
SIGCHLD:进程终止时向其父进程发送的信号,默认为忽略。父进程也可以捕捉该信号。
SIGFPE:  算术运算异常,如除数为0
SIGINT:  用户按下中断键,一般为 Ctrl + C
SIGSEGV:无效的内存引用
 

2.中断的系统调用

如果进程在执行一个低速系统调用而阻塞期间捕捉到一个信号,则该系统调用就中断不再执行
低速系统调用:读写某些类型文件(管道、终端、网络套接字)
 
again:
     if ((n = read(fd, buf, BUFSIZE)) < 0) {
         if (errno == EINTR)
             goto again;              /* just an interrupted system call */
         /* handle other errors */
}

3.使用longjmp,带超时限制调用read

  #include <stdio.h>
  #include <setjmp.h>
  #include <unistd.h>
  #include <signal.h>
  
  static jmp_buf env_alarm;
  static void sig_alarm(int signo)
  {
      longjmp(env_alarm, 1);
  }
  
int main(int argc, char* argv[])
  {
      char buf[4096];
      if (signal(SIGALRM, sig_alarm) == SIG_ERR) {
          fprintf(stderr, "signal(SIGALRM) error\n");
      } 
  
      if (setjmp(env_alarm) != 0) {
          fprintf(stderr, "read timeout\n");
          return -1;
      } 
      alarm(5);
      int nread = 0;
      if ((nread = read(STDIN_FILENO, buf, 4096)) < 0) {
          fprintf(stderr, "read error\n");
      } 
      alarm(0);
      write(STDOUT_FILENO, buf, nread);
      return 0;
  }

 

4.sigaction函数

sigaction函数用来检查或修改与指定信号相关联的处理动作

 

struct sigaction {
    void       (*sa_handler)(int);       /* addr of signal handler */
    sigset_t   sa_mask;                  /*  addtional signals to block */
    int        sa_flags;                 /*  signal options */
    void       (*sa_sigaction)(int, siginfo_t *, void *);     /* alternate handler */
};

 

posix使用sigaction实现signal(原有的signal函数语义不可靠)

typedef void Sigfunc(int);

Sigfunc* signal(int signo, Sigfunc* func)
{
    struct sigaction newact, oldact;
    newact.sa_handler = func;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
        newact.sa_flags |= SA_INTERRUPT;
#endif
    } else {
#ifdef SA_RESTART
        newact.sa_flags |= SA_RESTART;
#endif
    }   
    if (sigaction(signo, &newact, &oldact) < 0) {
        return (SIG_ERR);
    }   
    return oldact.sa_handler;
}

 

你可能感兴趣的:(学习笔记)