成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux-C 編程 | 3 分鐘快速了解信號驅動式 IO

系統
系統調用可能因為無法立即完成而被操作系統掛起,直到等待的事件發生為止。系統調用則總是立即返回,而不管事件是否已經發生。

[[384784]]

本文轉載自微信公眾號「嵌入式Hacker」,作者嵌入式Hacker。轉載本文請聯系嵌入式Hacker公眾號。

一、Linux 的 5 種 IO 模型

二、如何使用信號驅動式 I/O?

三、內核何時會發送 "IO 就緒" 信號?

四、最簡單的示例

五、擴展知識

一、Linux 的 5 種 IO 模型

阻塞式 I/O:

系統調用可能因為無法立即完成而被操作系統掛起,直到等待的事件發生為止。

非阻塞式 I/O (O_NONBLOCK):

系統調用則總是立即返回,而不管事件是否已經發生。

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

通過 I/O 復用函數向內核注冊一組事件,內核通過 I/O 復用函數把其中就緒的事件通知給應用程序。

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

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

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

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

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

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

二、如何使用信號驅動式 I/O?

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

1> 為通知信號安裝處理函數。

通過 sigaction() 來完成:

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

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

2> 為文件描述符的設置屬主。

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

  1. fcntl(fd, F_SETOWN, pid) 

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

pid 為正整數時,代表了進程 ID 號。

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

3> 使能非阻塞 I/O。

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

  1. flags = fcntl(fd, F_GETFL); 
  2. fcntl(fd, F_SETFL, flags | O_NONBLOCK); 

4> 使能信號驅動 I/O。

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

  1. flags = fcntl(fd, F_GETFL); 
  2. fcntl(fd, F_SETFL, flags | O_ASYNC); 

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

當 I/O 操作就緒時,內核會給進程發送一個信號,然后調用在第 1 步中安裝好的信號處理函數。

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

循環執行 I/O 系統調用直到失敗為止,此時錯誤碼為 EAGAIN 或 EWOULDBLOCK。

原因:

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

且當文件描述符收到 I/O 事件通知時,并不知道要處理多少 I/O 數據。

三、內核何時會發送 "IO 就緒" 信號?

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

1> 終端

對于終端,當有新的輸入時會會產生信號。

2> 管道和 FIFO

對于讀端,下列情況會產生信號:

  • 數據寫入到管道中;
  • 管道的寫端關閉;

對于寫端,下列情況會產生信號:

  • 對管道的讀操作增加了管道中的空余空間大小。
  • 管道的讀端關閉;

3> 套接字

對于 UDP 套接字,下列情況會產生信號:

  • 數據報到達套接字;
  • 套接字上發生異步錯誤;

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

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

四、最簡單的示例

信號處理函數:

  1. static volatile sig_atomic_t gotSigio = 0; 
  2.  
  3. static void handler(int sig) 
  4.     gotSigio = 1; 

主程序:

  1. int main(int argc, char *argv[]) 
  2.     int flags, j, cnt; 
  3.     struct termios origTermios; 
  4.     char ch; 
  5.     struct sigaction sa; 
  6.     int done; 
  7.  
  8.     /* Establish handler */ 
  9.     sigemptyset(&sa.sa_mask); 
  10.     sa.sa_flags = SA_RESTART; 
  11.     sa.sa_handler = handler; 
  12.     if (sigaction(SIGIO, &sa, NULL) == -1) { 
  13.         perror("sigaction()\n"); 
  14.         exit(1); 
  15.     } 
  16.  
  17.     /* Set owner process */ 
  18.     if (fcntl(STDIN_FILENO, F_SETOWN, getpid()) == -1) { 
  19.         perror("fcntl() / F_SETOWN\n"); 
  20.         exit(1); 
  21.     } 
  22.  
  23.     /* Enable "I/O possible" signaling and make I/O nonblocking */ 
  24.     flags = fcntl(STDIN_FILENO, F_GETFL); 
  25.     if (fcntl(STDIN_FILENO, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1) { 
  26.         perror("fcntl() / F_SETFL\n"); 
  27.         exit(1); 
  28.     } 
  29.  
  30.     for (done = 0, cnt = 0; !done ; cnt++) { 
  31.         sleep(1); 
  32.  
  33.         if (gotSigio) { 
  34.             gotSigio = 0; 
  35.  
  36.             /* Read all available input until error (probably EAGAIN) 
  37.                or EOF */ 
  38.             while (read(STDIN_FILENO, &ch, 1) > 0 && !done) { 
  39.                 printf("cnt=%d; read %c\n", cnt, ch); 
  40.                 done = ch == '#'
  41.             } 
  42.         } 
  43.     } 
  44.     exit(0); 

運行效果:

  1. ./build/sigio  
  2. cnt=0; read a 
  3. cnt=0; read  
  4.  
  5. abc 
  6. cnt=4; read a 
  7. cnt=4; read b 
  8. cnt=4; read c 
  9. cnt=4; read  
  10.  
  11. cnt=7; read # 

該程序會先使能信號驅動 IO,然后循環執行計數操作。

當有 IO 就緒信號到來時,會去終端讀取數據并打印出來,然后繼續執行計數操作。

五、擴展知識

I/O 多路復用 、信號驅動 I/O 以及 epoll 機制可用于監視多個文件描述符。

它們并不實際執行 I/O 操作,當某個文件描述符處于就緒態,仍需采用傳統的 I/O 系統調用來完成 I/O 操作。

相比 I/O 多路復用,當監視大量的文件描述符時信號驅動 I/O 有著顯著的性能優勢,原因是內核能夠幫進程記錄了正在監視的文件描述符列表。

信號驅動 I/O 的缺點:

  • 信號的處理流程較為復雜;
  • 無法指定需要監控的事件類型。

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

六、相關參考

UNIX 網絡編程卷1

  • 6.2 I/O模型
  • 25 信號驅動式I/O

Linux-UNIX 系統編程手冊

  • 63 其他備選的I/O模型

Linux 高性能服務器編程

  • 8.3 I/O 模型

Linux 多線程服務端編程_使用muduo C++網絡庫

  • 7.4.1 muduo的IO模型

 

責任編輯:武曉燕 來源: 嵌入式Hacker
相關推薦

2021-03-31 09:10:25

UI設計經驗

2016-12-30 13:43:35

異步編程RxJava

2016-08-11 10:11:07

JavaScript函數編程

2016-08-11 10:34:37

Javascript函數編程

2009-11-12 10:05:09

Visual C++

2023-11-28 09:17:05

Linux編程

2018-05-06 16:26:03

關聯規則數據分析關聯規則推薦

2020-10-18 07:13:44

Linux系統編程信號捕捉

2024-01-09 18:09:43

模型方式DMA

2020-07-17 07:44:25

云計算邊緣計算IT

2021-01-27 18:15:01

Docker底層宿主機

2020-03-23 15:18:26

知識圖譜Web

2017-10-26 08:53:38

前端JavaScript函數式編程

2018-07-02 15:18:39

Linux文件系統

2022-09-08 11:12:09

ES6JavaScript

2024-11-07 16:09:53

2020-09-25 07:34:40

Linux系統編程信號量

2021-01-06 05:23:15

ServiceMesh網絡阿帕網

2017-03-01 13:06:39

Linux驅動技術DMA編程

2023-02-13 09:01:29

Linux驅動實例
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲高清一区二区三区 | www久久久 | 天天爱爱网 | 亚洲精品一区二区三区在线 | 午夜影院在线 | 91精品国产欧美一区二区成人 | 农夫在线精品视频免费观看 | 欧美日韩成人影院 | 完全免费在线视频 | a久久 | 精品一区二区三区不卡 | www.色综合| av一级久久 | 午夜视频免费在线观看 | 91福利网址 | 久久亚洲欧美日韩精品专区 | 成人午夜精品 | 国产精品亚洲片在线播放 | 亚洲网址在线观看 | 国产日韩一区二区三区 | 国产成人精品免费视频大全最热 | 亚洲69p | 黑人精品欧美一区二区蜜桃 | 神马久久久久久久久久 | 一区二区久久精品 | 日韩在线 | 久久久久国产 | 欧洲亚洲一区二区三区 | 久久精品一区 | h视频在线观看免费 | 日本一区二区视频 | 一区二区三区在线免费 | 欧美a在线看 | 久久夜色精品国产 | 99免费精品视频 | 精品国产视频 | a级在线免费视频 | 色欧美综合| 7799精品视频天天看 | 日韩精品一区二区三区在线观看 | www.4hu影院|