日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

C/C++ Linux 异步IO(AIO)

發布時間:2023/12/10 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C/C++ Linux 异步IO(AIO) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.select和poll

IO多路轉換技術, select, poll的原理是: 通過將待監聽文件描述符(fd)加入集合, 然后通過查詢其調用返回值, 取得數據有動靜的fd數量, 再輪詢集合中每個fd, 如果有數據, 就直接讀取; 如果沒有數據, 就等待下一次查詢.
select和poll實現了異步形式通知, 但本質上還是需要主動輪詢.

2. BSD異步IO

System V和BSD都有一套各自的異步IO, 原理類似, 這里只介紹BSD異步IO.
BSD異步IO是信號SIGIO, SIGURG的組合: SIGIO 通用異步IO信號; SIGURG 用來通知進程網絡連接上的帶外數據(data of band, 緊急數據)已經達到.

進程接收SIGIO信號, 需要執行的步驟:

  • 調用signal/sigaction為SIGIO信號建立處理程序;
  • 調用fcntl, 命令參數F_SETOWN, 設置進程ID或進程組ID, 用于告訴驅動程序/內核, 指定進程接收SIGIO信號;
  • 調用fcntl, 命令參數F_SETFL, 設置O_ASYNC文件狀態標識, 以便在該fd上可以進行異步IO;
  • 進程接收SIGURG, 只需只需第1,2步. 信號僅對引用支持帶外數據的網絡連接描述符 產生, 如TCP連接(UDP不支持).

    BSD異步IO例程
    完整源代碼, 請參見?async.c
    關鍵步驟代碼

    void sig_fun() {int data = 0;int n = read(mousefd, &data, sizeof(data));if (n < 0) {printf("read mouse error\n");}else {printf("%d\n", data);} }struct sigaction sa; struct sigaction od_sa;sa.sa_handler = sig_fun; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGIO); // SIGIO添加進信號集 sa.sa_flags = 0;// 1. 調用sigaction為SIGIO信號建立信號處理程序 sigaction(SIGIO, &sa, &od_sa); // 捕獲SIGIO后, 處理信號時, 阻塞信號; 處理完畢后恢復// 2. 以命令F_SETOWN調用fcntl來設置進程ID, 用于接收對該描述符的信號(SIGIO) if (fcntl(mousefd, F_SETOWN, getpid()) < 0) {perror("fcntl F_SETOWN error");exit(1); }// 3. 以命令F_SETFL調用fcntl, 設置O_ASYNC文件狀態標識, 使得在該描述符上可以進行異步IO int flag = fcntl(mousefd, F_GETFL); if (flag < 0) {perror("fcntl F_GETFL error");exit(1); } flag |= O_ASYNC;ret = fcntl(mousefd, F_SETFL, flag); if (ret < 0) {perror("fcntl F_SETFL error");exit(1); }while (1) {usleep(50); }

    3. POSIX異步IO(AIO)

    BSD對不同的設備文件進行異步IO方法不一樣, 如終端設備是產生SIGIO信號, 僅支持帶外數據的設備才能產生SIGURG信號.
    POSIX對不同類型文件進行異步IO提供一套一致的方法, SUSv4中, 這些接口被移到了基本部分中, 所以現在所有的平臺都被要求支持這些接口.

    3.1 AIO控制塊

    異步IO接口使用AIO控制塊來描述IO操作.
    AIO控制塊由aiocb結構定義:

    #include <aiocb.h>struct aiocb {/* The order of these fields is implementation-dependent */int aio_fildes; /* File descriptor */off_t aio_offset; /* File offset */volatile void *aio_buf; /* Location of buffer */size_t aio_nbytes; /* Length of transfer */int aio_reqprio; /* Request priority */struct sigevent aio_sigevent; /* Notification method */int aio_lio_opcode; /* Operation to be performed;lio_listio() only *//* Various implementation-internal fields not shown */ };

    字段說明
    aio_fildes 表示已打開的文件描述符, 用于讀/寫;
    aio_offset 讀寫操作從aio_offset指定的偏移量開始;
    aio_buf 用于讀寫操作轉存數據的緩沖區;
    aio_nbytes 緩沖區aio_buf的大小;
    aio_reqprio 應用程序使用該字段為異步IO請求提示順序. 值必須介于0和sysconf(_SC_AIO_PRIO_DELTA_MAX)返回值之間. 文件同步操作忽略該字段;
    aio_lio_opcode 應當進行的操作類型, 只能用于lio_listio (基于列表的異步IO), 值描述見lio_listio章節;
    aio_sigevent 指明IO事件完成后, 如何通知應用程序.
    sigevent結構:

    union sigval { /* Data passed with notification */int sival_int; /* Integer value */void *sival_ptr; /* Pointer value */ };struct sigevent {int sigev_notify; /* Notification method */int sigev_signo; /* Notification signal */union sigval sigev_value; /* Data passed withnotification */void (*sigev_notify_function) (union sigval);/* Function used for thread notification (SIGEV_THREAD) */void *sigev_notify_attributes;/* Attributes for notification thread (SIGEV_THREAD) */pid_t sigev_notify_thread_id;/* ID of thread to signal (SIGEV_THREAD_ID) */ };

    sigevent字段說明:
    -sigev_notify 通知類型, 其取值只能是這3個之一: SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD.
    1)SIGEV_NONE 異步IO請求完成后, 不通知進程;
    2)SIGEV_SIGNAL 異步IO請求完成后, 產生由sigev_signo字段指定的信號. 也就是說, 需要應用程序捕捉sigev_signo表示的信號, 并在信號處理程序中完成IO數據操作.
    3)SIGEV_THREAD 異步IO請求完成時, 調用sigev_notify_function指定的函數, sigev_value作為唯一參數被傳入. 除非sigev_notify_attributes字段被設定為pthread屬性結構的地址, 且該結構指定了一個另外的線程屬性, 否則該函數將在線程分離狀態的一個單獨的線程中執行.

    3.2 aio_read & aio_write

    使用異步IO前, 應先對AIO控制塊(struct aiocb對象)進行初始化.

    aio_read - 異步讀, aio_write - 異步寫:

    #include <aio.h>int aio_read(struct aiocb *aiocb);int aio_write(struct aiocb *aiocb);

    描述
    將異步IO請求放入等待處理的隊列中(函數提出請求, 由OS放入). 函數返回值與實際IO操作結果沒有關系. IO操作等待時, 需確保AIO控制塊和數據緩沖區保持穩定, 下面對應的內容也必須始終合法, 不能被釋放, 也不能被復用, 除非IO操作完成.
    aio_read是read的異步模擬, aio_write是write的異步模擬.

    read(fd, buf, count); write(fd, buf, n);

    返回值
    成功返回0; 失敗-1

    3.3 aio_fsync

    aio_fsync - 異步文件同步:
    強制所有(等待隊中)等待的異步操作不等待, 而直接寫入持久化的存儲中(通常指磁盤, emmc等), 可以設置一個AIO控制塊并調用aio_fsync.

    #include <aio.h>int aio_fsync(int ap, struct aiocb *aiocb);

    描述
    aiocb->aio_fildes字段(文件描述符)指定異步寫操作被同步的文件.
    如果op = O_DSYNC, 那么操作執行像調用fdatasync, 函數立即返回, 但IO操作完成前, 文件數據不會被持久化;
    如果op = O_SYNC, 那么操作執行像調用fsync, 函數立即返回, 但IO操作完成前, 文件數據和屬性不會被持久化;

    sync, fsync, fdatasync, fflush是什么?
    參考sync、fsync、fdatasync、fflush函數區別和使用舉例 | CSDN

    函數名稱作用描述
    sync將所有修改過的(內核)快緩存區排隊進寫隊列, 然后返回, 并不等待實際寫磁盤操作結束
    fsync只對由fd指定單一文件起作用, 并且等待磁盤操作結束, 然后返回
    fdatasync類似于fsync, 但只影響文件的數據部分, 不像fsync還會同步更新文件的屬性
    fflush沖刷IO庫緩存, 將庫緩存內容寫入內核緩沖區

    3.4 aio_error

    aio_error - 獲取異步IO操作(異步讀、寫或同步)的完成狀態

    #include <aio.h>int aio_error(const struct aiocb *aiocb);

    描述
    函數返回異步IO請求的錯誤狀態, aiocb指向AIO控制塊, 代表了異步IO請求信息.

    返回值
    0 異步操作成功, 需要調用aio_return 函數獲取操作返回值;
    -1 對aio_error調用失敗, errno被設置;
    EINPROGRESS 異步讀、寫或同步操作仍在等待;
    其他值 相關異步操作失敗返回的錯誤碼(errno);

    3.5 aio_return

    aio_error提到, 返回0時表示異步操作成功, 可以調用aio_return獲取操作返回值.
    aio_return - 獲取異步IO操作返回值

    int <aio.h>int aio_return(const struct aiocb *aiocb);

    描述
    注意:

  • 異步操作完成之前, 不要調用aio_return, 其行為是未定義的;
  • 對每個異步操作調用一次aio_return, 因為一旦調用了, OS就能釋放包含了IO操作返回值的記錄;
  • 返回值
    失敗返回-1, errno被設置; 成功時, 返回異步操作結果, 即返回(同步版本)read、write或fsync在被成功調用時可能返回的結果.

    3.6 aio_suspend

    aio_suspend - 等待異步IO操作完成, 或超時

    #include <aio.h>int aio_suspend(const struct aiocb *const list[], int nent, const strct timespec *timeout);

    描述
    執行IO操作時, 如果有其他事務處理而不想被IO操作阻塞, 可以使用異步IO. 如果事務執行完畢后, 還有異步操作尚未完成時, 可調用aio_suspend函數阻止進程, 直到操作完成.

    參數
    list 指向AIO控制塊數組的指針
    nent 表明數組的元素個數
    timeout 超時時間

    返回值
    3種情況:

  • 如果被一個信號中斷, 返回-1, errno設置為EINTR;
  • 如果沒有任何IO操作完成, 阻塞時間超時, 返回-1, errno設置為EAGAIN;
  • 如果有任何IO操作完成, 返回0; 如果所有的異步IO操作都已完成, aio_suspend將在不阻塞的情況下直接返回;
  • 3.7 aio_cancel

    aio_cancel - 取消未完成的異步IO請求

    #include <aio.h>int aio_cancel(int fd, struct aiocb *aiocb);

    描述
    如果不想完成還在等待中的異步IO操作時, 可以調用aio_cancel嘗試取消. 描述為嘗試, 是因為系統無法保證一定能取消正在進行的任何操作.
    如果異步IO操作成功取消, 相應AIO控制塊調用aio_error將返回錯誤ECANCELED; 如果操作不能被取消, 那么相應的AIO控制塊不會被修改

    參數
    fd 指定未完成的異步IO操作的文件描述符
    aiocb 如果aiocb = NULL, 系統會嘗試取消所有該文件上未完成的異步IO操作; 其他情況, 系統將嘗試取消aiocb指向的單個AIO控制塊描述的單個異步IO操作.

    返回值
    4個值之一:
    AIO_ALLDONE 所有操作在嘗試取消前, 已經完成;
    AIO_CANCELED 所有要求的操作已被取消;
    AIO_NOTCANCELED 至少有一個要求的操作沒有被取消;
    -1 對aio_cancel調用失敗, 設置errno;

    3.8 lio_listio

    lio_listio - 初始化io請求列表

    #include <aio.h>int lio_listio(int mode, struct aiocb *const aiocb_list[], int nitems, struct sigevent *sevp);

    描述
    既能以同步方式使用, 也能以異步的方式使用. 函數提交一系列由一個AIO控制塊列表描述的IO請求.
    每個AIO控制塊中, aio_lio_opcode字段指定了該操作是一個讀操作(LIO_READ), 寫操作(LIO_WRITE), 還是將忽略的空操作(LIO_NOP). 讀操作, 會按照對應的AIO控制塊被傳給aio_read來處理; 寫操作, 會被傳給aio_write處理.

    參數
    mode 決定IO釋放真的是異步的. 取值說明:

  • LIO_WAIT 調用塊將等到所有操作完成, sevp參數將會被忽略;
  • LIO_NOWAIT IO請求入隊后, 立即返回, 進程在所有IO操作完成后, 按sigev指定的, 被異步通知. 如果不想被通知, sigev可設置為NULL. 被sigev指定的異步通知, 是在每個AIO控制塊本身的異步通知之外的.
  • aiocb_list 指向AIO控制塊列表, 指定了要運行的IO操作.

    nitems 指定了aiocb_list數組元素格式.

    實現限制
    實現一般會限制一些參數的實際取值
    POSIX.1中異步IO運行時不變量的值

    名稱描述可接受的最小值
    AIO_LISTIO_MAX單個列表IO調用中的最大IO操作數_POSIX_AOI_LISTIO_MAX
    AIO_MAX未完成的異步IO操作的最大數目_POSIX_AIO_MAX
    AIO_PRIO_DELTA_MAX進程可以減少的異步IO優先級的最大值0

    4. AIO的使用例程

    以從一個文件讀取數據, 然后寫到另外一個文件為例.

    4.1 同步IO操作

    流程

    4.2 異步IO操作 (AIO)

    流程


    ?

    更多C/C++Linux后臺開發架構體系學習文章請關注筆者:

    Linux后臺開發獅?www.zhihu.com/people/linux-9-85正在上傳…重新上傳取消

    筆者會不斷更新C/C++Linux后臺開發架構體系,程序員面試經驗以及答題答案總結分享;敬請關注更新。

    總結

    以上是生活随笔為你收集整理的C/C++ Linux 异步IO(AIO)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。