《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 嵌入式技術(shù) > 其他 > Linux教學(xué)—— 3 分鐘快速了解信號驅(qū)動式 IO

Linux教學(xué)—— 3 分鐘快速了解信號驅(qū)動式 IO

2022-08-12
來源:FPGA之家
關(guān)鍵詞: Linux 驅(qū)動式IO

  以下是正文:

  一、Linux 的 5 種 IO 模型

  二、如何使用信號驅(qū)動式 I/O?

  三、內(nèi)核何時會發(fā)送 "IO 就緒" 信號?

  四、最簡單的示例

  五、擴展知識

  一、Linux 的 5 種 IO 模型

  阻塞式 I/O:

  系統(tǒng)調(diào)用可能因為無法立即完成而被操作系統(tǒng)掛起,直到等待的事件發(fā)生為止。

微信圖片_20220812143203.png

  非阻塞式 I/O (O_NONBLOCK):

  系統(tǒng)調(diào)用則總是立即返回,而不管事件是否已經(jīng)發(fā)生。

微信圖片_20220812143228.png

  I/O 復(fù)用 (select、poll、epoll):

  通過 I/O 復(fù)用函數(shù)向內(nèi)核注冊一組事件,內(nèi)核通過 I/O 復(fù)用函數(shù)把其中就緒的事件通知給應(yīng)用程序。

微信圖片_20220812143308.png

  信號驅(qū)動式 I/O (SIGIO):

  為一個目標(biāo)文件描述符指定宿主進程,當(dāng)文件描述符上有事件發(fā)生時,SIGIO 的信號處理函數(shù)將被觸發(fā),然后便可對目標(biāo)文件描述符執(zhí)行 I/O 操作。

  微信圖片_20220812143329.png

  異步 I/O (POSIX 的 aio_ 系列函數(shù)):

  異步 I/O 的讀寫操作總是立即返回,而不論 I/O 是否是阻塞的,真正的讀寫操作由內(nèi)核接管。

  微信圖片_20220812143450.png

  思考一下,什么時候應(yīng)該選擇何種 I/O 模型?為何要這么選擇?

  下面重點關(guān)注信號驅(qū)動式 I/O 這一模型,其他模型可查閱文末參考書籍。

  二、如何使用信號驅(qū)動式 I/O?

  一般通過如下 6 個步驟來使用信號驅(qū)動式 I/O 模型。

  1> 為通知信號安裝處理函數(shù)。

  通過 sigaction() 來完成:

  int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

  默認情況下,這個通知信號為 SIGIO。

  2> 為文件描述符的設(shè)置屬主。

  通過 fcntl() 的 F_SETOWN 操作來完成:

  fcntl(fd, F_SETOWN, pid)

  屬主是當(dāng)文件描述符上可執(zhí)行 I/O 時,會接收到通知信號的進程或進程組。

  pid 為正整數(shù)時,代表了進程 ID 號。

  pid 為負整數(shù)時,它的絕對值就代表了進程組 ID 號。

  3> 使能非阻塞 I/O。

  通過 fcntl() 的 F_SETFL 操作來完成:

  flags = fcntl(fd, F_GETFL);

  fcntl(fd, F_SETFL, flags | O_NONBLOCK);

  4> 使能信號驅(qū)動 I/O。

  通過 fcntl() 的 F_SETFL 操作來完成:

  flags = fcntl(fd, F_GETFL);

  fcntl(fd, F_SETFL, flags | O_ASYNC);

  5> 進程等待 "IO 就緒" 信號的到來。

  當(dāng) I/O 操作就緒時,內(nèi)核會給進程發(fā)送一個信號,然后調(diào)用在第 1 步中安裝好的信號處理函數(shù)。

  6> 進程盡可能多地執(zhí)行 I/O 操作。

  循環(huán)執(zhí)行 I/O 系統(tǒng)調(diào)用直到失敗為止,此時錯誤碼為 EAGAIN 或 EWOULDBLOCK。

  原因:

  信號驅(qū)動 I/O 提供的是邊緣觸發(fā)通知,即只有當(dāng) I/O 事件發(fā)生時我們才會收到通知,

  且當(dāng)文件描述符收到 I/O 事件通知時,并不知道要處理多少 I/O 數(shù)據(jù)。

  三、內(nèi)核何時會發(fā)送 "IO 就緒" 信號?

  對于不同類型的文件描述符,情況不一樣。

  1> 終端

  對于終端,當(dāng)有新的輸入時會會產(chǎn)生信號。

  2> 管道和 FIFO

  對于讀端,下列情況會產(chǎn)生信號:

  數(shù)據(jù)寫入到管道中;管道的寫端關(guān)閉;

  對于寫端,下列情況會產(chǎn)生信號:

  對管道的讀操作增加了管道中的空余空間大小。管道的讀端關(guān)閉;

  3> 套接字

  對于 UDP 套接字,下列情況會產(chǎn)生信號:

  數(shù)據(jù)報到達套接字;套接字上發(fā)生異步錯誤;

  對于 TCP 套接字,信號驅(qū)動式 I/O 近乎無用。

  太多情況都會產(chǎn)生信號,而我們又無法得知事件類型,因此這里就不再列舉其產(chǎn)生信號的情況。

  四、最簡單的示例

  信號處理函數(shù):

  static volatile sig_atomic_t gotSigio = 0;

  static void handler(int sig)

  {

  gotSigio = 1;

  }

  主程序:

  int main(int argc, char *argv[])

  {

  int flags, j, cnt;

  struct termios origTermios;

  char ch;

  struct sigaction sa;

  int done;

  /* Establish handler */

  sigemptyset(&sa.sa_mask);

  sa.sa_flags = SA_RESTART;

  sa.sa_handler = handler;

  if (sigaction(SIGIO, &sa, NULL) == -1) {

  perror("sigaction()\n");

  exit(1);

  }

  /* Set owner process */

  if (fcntl(STDIN_FILENO, F_SETOWN, getpid()) == -1) {

  perror("fcntl() / F_SETOWN\n");

  exit(1);

  }

  /* Enable "I/O possible" signaling and make I/O nonblocking */

  flags = fcntl(STDIN_FILENO, F_GETFL);

  if (fcntl(STDIN_FILENO, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1) {

  perror("fcntl() / F_SETFL\n");

  exit(1);

  }

  for (done = 0, cnt = 0; !done ; cnt++) {

  sleep(1);

  if (gotSigio) {

  gotSigio = 0;

  /* Read all available input until error (probably EAGAIN)

  or EOF */

  while (read(STDIN_FILENO, &ch, 1) > 0 && !done) {

  printf("cnt=%d; read %c\n", cnt, ch);

  done = ch == '#';

  }

  }

  }

  exit(0);

  }

  運行效果:

  ./build/sigio

  a

  cnt=0; read a

  cnt=0; read

  abc

  cnt=4; read a

  cnt=4; read b

  cnt=4; read c

  cnt=4; read

  #

  cnt=7; read #

  該程序會先使能信號驅(qū)動 IO,然后循環(huán)執(zhí)行計數(shù)操作。

  當(dāng)有 IO 就緒信號到來時,會去終端讀取數(shù)據(jù)并打印出來,然后繼續(xù)執(zhí)行計數(shù)操作。

  五、擴展知識

  I/O 多路復(fù)用 、信號驅(qū)動 I/O 以及 epoll 機制可用于監(jiān)視多個文件描述符。

  它們并不實際執(zhí)行 I/O 操作,當(dāng)某個文件描述符處于就緒態(tài),仍需采用傳統(tǒng)的 I/O 系統(tǒng)調(diào)用來完成 I/O 操作。

  相比 I/O 多路復(fù)用,當(dāng)監(jiān)視大量的文件描述符時信號驅(qū)動 I/O 有著顯著的性能優(yōu)勢,原因是內(nèi)核能夠幫進程記錄了正在監(jiān)視的文件描述符列表。

  信號驅(qū)動 I/O 的缺點:

  信號的處理流程較為復(fù)雜;

  無法指定需要監(jiān)控的事件類型。

  Linux 特有的 epoll 是一個更好的選擇。

  六、相關(guān)參考

  UNIX 網(wǎng)絡(luò)編程卷1

  6.2 I/O模型25 信號驅(qū)動式I/O

  Linux-UNIX 系統(tǒng)編程手冊

  63 其他備選的I/O模型

  Linux 高性能服務(wù)器編程

  8.3 I/O 模型

  Linux 多線程服務(wù)端編程_使用muduo C++網(wǎng)絡(luò)庫

  7.4.1 muduo的IO模型

  更多信息可以來這里獲取==>>電子技術(shù)應(yīng)用-AET<<

微信圖片_20210517164139.jpg

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認版權(quán)者。如涉及作品內(nèi)容、版權(quán)和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟損失。聯(lián)系電話:010-82306118;郵箱:[email protected]
主站蜘蛛池模板: 国产精品资源 | 久久成人免费观看草草影院 | 久久网免费 | 91成人免费观看 | 久久亚洲国产成人亚 | 久久国产精品女 | 欧美日韩在线视频观看 | 亚洲国产爱久久全部精品 | 她也啪在线视频 | 欧美牛逼aa| 韩日黄色 | 欧美成人午夜视频免看 | 成人区精品一区二区毛片不卡 | 亚洲精品日本高清中文字幕 | 欧美成人久久一级c片免费 欧美成人看片黄a免费 | 欧美一级免费看 | 亚洲最新在线视频 | 三级c欧美做人爱视频 | 一级做a爰片久久毛片 | 日本高清视频在线观看 | 国产国语在线播放视频 | 欧美一级毛片生活片 | 久久免费小视频 | 亚洲一级网站 | 韩国免又爽又刺激激情视频 | 另类亚洲视频 | 国产欧美综合精品一区二区 | 日韩精品无码一区二区三区 | 男人添女人下面免费毛片 | 国产末成年女噜噜片 | 黄色激情网站 | 国产精品网址 | 黄色日韩网站 | 在线亚洲精品国产波多野结衣 | 女人张开腿男人猛桶视频 | 国产一级做a爰片在线 | 国产成人无精品久久久久国语 | 亚州视频一区 | 亚洲第一中文字幕 | 国产成人久久精品 | 欧美一级毛片高清免费观看 |