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;
}
相關文章
相關標籤/搜索