1. <menuitem id="edugg"><ins id="edugg"><delect id="edugg"></delect></ins></menuitem> <progress id="edugg"></progress>

      <samp id="edugg"><ins id="edugg"></ins></samp>
      <samp id="edugg"></samp>
        <menuitem id="edugg"></menuitem>
        <dl id="edugg"></dl>

        《電子技術應用》
        您所在的位置:首頁 > 嵌入式技術 > 其他 > Linux教學—— 3 分鐘快速了解信號驅動式 IO

        Linux教學—— 3 分鐘快速了解信號驅動式 IO

        2022-08-12
        來源:FPGA之家
        關鍵詞: Linux 驅動式IO

          以下是正文:

          一、Linux 的 5 種 IO 模型

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

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

          四、最簡單的示例

          五、擴展知識

          一、Linux 的 5 種 IO 模型

          阻塞式 I/O:

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

        微信圖片_20220812143203.png

          非阻塞式 I/O (O_NONBLOCK):

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

        微信圖片_20220812143228.png

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

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

        微信圖片_20220812143308.png

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

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

          微信圖片_20220812143329.png

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

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

          微信圖片_20220812143450.png

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

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

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

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

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

          通過 sigaction() 來完成:

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

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

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

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

          fcntl(fd, F_SETOWN, pid)

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

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

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

          3> 使能非阻塞 I/O。

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

          flags = fcntl(fd, F_GETFL);

          fcntl(fd, F_SETFL, flags | O_NONBLOCK);

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

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

          flags = fcntl(fd, F_GETFL);

          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 近乎無用。

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

          四、最簡單的示例

          信號處理函數:

          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 #

          該程序會先使能信號驅動 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模型

          更多信息可以來這里獲取==>>電子技術應用-AET<<

        微信圖片_20210517164139.jpg

        本站內容除特別聲明的原創文章之外,轉載內容只為傳遞更多信息,并不代表本網站贊同其觀點。轉載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創文章及圖片等內容無法一一聯系確認版權者。如涉及作品內容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經濟損失。聯系電話:010-82306116;郵箱:aet@chinaaet.com。
        国产野外无码激情理论片

        1. <menuitem id="edugg"><ins id="edugg"><delect id="edugg"></delect></ins></menuitem> <progress id="edugg"></progress>

          <samp id="edugg"><ins id="edugg"></ins></samp>
          <samp id="edugg"></samp>
            <menuitem id="edugg"></menuitem>
            <dl id="edugg"></dl>