前言
慢系統調用,指的是可能永遠無法返回,從而使進程永遠阻塞的系統調用,比如無客戶連接時的accept、無輸入時的read都屬于慢速系統調用。
在Linux中,當阻塞于某個慢系統調用的進程捕獲一個信號,則該系統調用就會被中斷,轉而執行信號處理函數,這就是被中斷的系統調用。
然而,當信號處理函數返回時,有可能發生以下的情況:
如果信號處理函數是用signal注冊的,系統調用會自動重啟,函數不會返回 如果信號處理函數是用sigaction注冊的 默認情況下,系統調用不會自動重啟,函數將返回失敗,同時errno被置為EINTR 只有中斷信號的SA_RESTART標志有效時,系統調用才會自動重啟下面我們編寫代碼,分別驗證上述幾種情形,其中系統調用選擇read,中斷信號選擇SIGALRM,中斷信號由alarm產生。
使用signal
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <errno.h>void handler(int s){  printf("read is interrupt by signal handler/n");  return;}int main(){  char buf[10];  int nread = 0;  signal(SIGALRM, handler);  alarm(2);  printf("read start/n");  nread = read(STDIN_FILENO, buf, sizeof(buf));  printf("read return/n");  if ((nread < 0) && (errno == EINTR))  {    printf("read return failed, errno is EINTR/n");  }  return 0;}
使用sigaction + 默認情況
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <errno.h>void handler(int s){  printf("read is interrupt by signal handler/n");  return;}int main(){  char buf[10];  int nread = 0;  struct sigaction act;  sigemptyset(&act.sa_mask);  act.sa_handler = handler;  act.sa_flags = 0; //不給SIGALRM信號設置SA_RESTART標志,使用sigaction的默認處理方式  //act.sa_flag |= SA_INTERRUPT; //SA_INTERRUPT是sigaction的默認處理方式,即不自動重啟被中斷的系統調用  //實際上,不管act.sa_flags值為多少,只要不設置SA_RESTART,sigaction都是按SA_INTERRUPT處理的  sigaction(SIGALRM, &act, NULL);  alarm(2);  printf("read start/n");  nread = read(STDIN_FILENO, buf, sizeof(buf));  printf("read return/n");  if ((nread < 0) && (errno == EINTR))  {    printf("read return failed, errno is EINTR/n");  }  return 0;}
使用sigaction + 指定SA_RESTART標志
#include <stdio.h>#include <signal.h>#include <unistd.h>#include <errno.h>void handler(int s){  printf("read is interrupt by signal handler/n");  return;}int main(){  char buf[10];  int nread = 0;  struct sigaction act;  sigemptyset(&act.sa_mask);  act.sa_handler = handler;  act.sa_flags = 0;  act.sa_flags |= SA_RESTART; //給SIGALRM信號設置SA_RESTART標志  sigaction(SIGALRM, &act, NULL);  alarm(2);  printf("read start/n");  nread = read(STDIN_FILENO, buf, sizeof(buf));  printf("read return/n");  if ((nread < 0) && (errno == EINTR))  {    printf("read return failed, errno is EINTR/n");  }  return 0;}
新聞熱點
疑難解答