Linux被中斷的系統(tǒng)如何調(diào)用詳解
前言
慢系統(tǒng)調(diào)用,指的是可能永遠(yuǎn)無(wú)法返回,從而使進(jìn)程永遠(yuǎn)阻塞的系統(tǒng)調(diào)用,比如無(wú)客戶連接時(shí)的accept、無(wú)輸入時(shí)的read都屬于慢速系統(tǒng)調(diào)用。
在Linux中,當(dāng)阻塞于某個(gè)慢系統(tǒng)調(diào)用的進(jìn)程捕獲一個(gè)信號(hào),則該系統(tǒng)調(diào)用就會(huì)被中斷,轉(zhuǎn)而執(zhí)行信號(hào)處理函數(shù),這就是被中斷的系統(tǒng)調(diào)用。
然而,當(dāng)信號(hào)處理函數(shù)返回時(shí),有可能發(fā)生以下的情況:
- 如果信號(hào)處理函數(shù)是用signal注冊(cè)的,系統(tǒng)調(diào)用會(huì)自動(dòng)重啟,函數(shù)不會(huì)返回
- 如果信號(hào)處理函數(shù)是用sigaction注冊(cè)的
- 默認(rèn)情況下,系統(tǒng)調(diào)用不會(huì)自動(dòng)重啟,函數(shù)將返回失敗,同時(shí)errno被置為EINTR
- 只有中斷信號(hào)的SA_RESTART標(biāo)志有效時(shí),系統(tǒng)調(diào)用才會(huì)自動(dòng)重啟
下面我們編寫代碼,分別驗(yàn)證上述幾種情形,其中系統(tǒng)調(diào)用選擇read,中斷信號(hào)選擇SIGALRM,中斷信號(hào)由alarm產(chǎn)生。
使用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 + 默認(rèn)情況
#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信號(hào)設(shè)置SA_RESTART標(biāo)志,使用sigaction的默認(rèn)處理方式 //act.sa_flag |= SA_INTERRUPT; //SA_INTERRUPT是sigaction的默認(rèn)處理方式,即不自動(dòng)重啟被中斷的系統(tǒng)調(diào)用 //實(shí)際上,不管act.sa_flags值為多少,只要不設(shè)置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標(biāo)志
#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信號(hào)設(shè)置SA_RESTART標(biāo)志 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; }
由于對(duì)被中斷系統(tǒng)調(diào)用處理方式的差異性,因此對(duì)應(yīng)用程序來(lái)說(shuō),與被中斷的系統(tǒng)調(diào)用相關(guān)的問(wèn)題是:
- 應(yīng)用程序無(wú)法保證總是知道信號(hào)處理函數(shù)的注冊(cè)方式,以及是否設(shè)置了SA_RESTART標(biāo)志
- 可移植的代碼必須顯式處理關(guān)鍵函數(shù)的出錯(cuò)返回,當(dāng)函數(shù)出錯(cuò)且errno等于EINTR時(shí),可以根據(jù)實(shí)際需求進(jìn)行相應(yīng)處理,比如重啟該函數(shù)
int nread = read(fd, buf, 1024); if (nread < 0) { if (errno == EINTR) { //read被中斷,其實(shí)不應(yīng)該算作失敗,可以根據(jù)實(shí)際需求進(jìn)行處理,比如重寫調(diào)用read,也可以忽略它 } else { //read真正的讀錯(cuò)誤 } }
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
deepin20 安裝英偉達(dá)閉源驅(qū)動(dòng)的步驟詳解
這篇文章主要介紹了deepin20 安裝英偉達(dá)閉源驅(qū)動(dòng)的步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09linux修改root密碼和linux忘記root密碼后找回密碼的方法
這篇文章主要介紹了linux修改root密碼和linux忘記root密碼后找回密碼的方法,需要的朋友可以參考下2014-01-01Linux下使用使用socket實(shí)現(xiàn)TCP服務(wù)端的示例代碼
套接字(socket)是 Linux 下的一種進(jìn)程間通信機(jī)制(socket IPC),它不僅支持同一主機(jī)的不同進(jìn)程間通信,還支持跨網(wǎng)絡(luò)的不同主機(jī)的進(jìn)程間通信,本文介紹了 Linux 下使用 socket 接口實(shí)現(xiàn) TCP 服務(wù)端的示例程序,需要的朋友可以參考下2024-03-03APACHE 自定義404錯(cuò)誤頁(yè)面設(shè)置方法
自定義404頁(yè)面返回不當(dāng)狀態(tài)碼如200等給網(wǎng)站最終SEO效果帶來(lái)的不利影響,因此,確保自定義的404錯(cuò)誤頁(yè)面能夠返回404狀態(tài)碼是極為重要的,也是網(wǎng)站優(yōu)化與SEO的基本要求2017-03-03Linux系統(tǒng)下使用rpm方式安裝最新mysql5.7.17完整步驟
這篇文章主要介紹了Linux系統(tǒng)下使用rpm方式安裝最新mysql5.7.17完整步驟,需要的朋友可以參考下2017-01-01Linux中BT5關(guān)于修改靜態(tài)IP和DNS方法
本篇文章給大家整理了關(guān)于Linux中BT5關(guān)于修改靜態(tài)IP和DNS的方法,有需要的朋友可以參考學(xué)習(xí)下。2018-02-02