溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux被中斷的系統如何調用詳解

發布時間:2020-09-12 09:02:05 來源:腳本之家 閱讀:166 作者:原野追逐 欄目:服務器

前言

慢系統調用,指的是可能永遠無法返回,從而使進程永遠阻塞的系統調用,比如無客戶連接時的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;
}

Linux被中斷的系統如何調用詳解

使用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;
}

Linux被中斷的系統如何調用詳解

使用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;
}

Linux被中斷的系統如何調用詳解

由于對被中斷系統調用處理方式的差異性,因此對應用程序來說,與被中斷的系統調用相關的問題是:

  • 應用程序無法保證總是知道信號處理函數的注冊方式,以及是否設置了SA_RESTART標志
  • 可移植的代碼必須顯式處理關鍵函數的出錯返回,當函數出錯且errno等于EINTR時,可以根據實際需求進行相應處理,比如重啟該函數
int nread = read(fd, buf, 1024);

if (nread < 0)
{
  if (errno == EINTR)
  {
    //read被中斷,其實不應該算作失敗,可以根據實際需求進行處理,比如重寫調用read,也可以忽略它
  }
  else
  {
    //read真正的讀錯誤
  }
}

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女