linux非同步IO程式設計例項分析

2021-07-11 08:42:50 字數 3800 閱讀 4289

在direct io模式下,非同步是非常有必要的(因為繞過了pagecache,直接和磁碟互動)。linux native aio正是基於這種場景設計的,具體的介紹見:kernel

asynchronousi/

o(aio)

support

forlinux。下面我們就來分析一下aio程式設計的相關知識。

阻塞模式下的io過程如下:

int fd = open(const char *pathname, int flags, mode_t mode);

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

int close(int fd);

因為整個過程會等待read/write的返回,所以不需要任何額外的資料結構。但非同步io的思想是:應用程式不能阻塞在昂貴的系統呼叫上讓cpu睡大覺,而是將io操作抽象成乙個個的任務單元提交給核心,核心完成io任務後將結果放在應用程式可以取到的地方。這樣在底層做i/o的這段時間內,cpu可以去幹其他的計算任務。但非同步的io任務批量的提交和完成,必須有自身可描述的結構,最重要的兩個就是iocb和io_event。

struct iocb u;

};

struct io_iocb_common ;

iocb是提交io任務時用到的,可以完整地描述乙個io請求:

data是留給用來自定義的指標:可以設定為io完成後的callback函式;

aio_lio_opcode表示操作的型別:io_cmd_pwrite | io_cmd_pread;

aio_fildes是要操作的檔案:fd;

io_iocb_common中的buf, nbytes, offset分別記錄的io請求的mem buffer,大小和偏移。

struct io_event ;

io_event是用來描述返回結果的:

obj就是之前提交io任務時的iocb;

res和res2來表示io任務完成的狀態。

libaio提供的api有:io_setup, io_submit, io_getevents, io_destroy。

1. 建立io任務

int io_setup (int maxevents, io_context_t *ctxp);

io_context_t對應核心中乙個結構,為非同步io請求提供上下文環境。注意在setup前必須將io_context_t初始化為0。

當然,這裡也需要open需要操作的檔案,注意設定o_direct標誌。

2.提交io任務

long io_submit (aio_context_t ctx_id, long nr, struct iocb **iocbpp);

提交任務之前必須先填充iocb結構體,libaio提供的包裝函式說明了需要完成的工作:

void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)

void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)

這裡注意讀寫的buf都必須是按扇區對齊的,可以用posix_memalign來分配。

3.獲取完成的io

long io_getevents (aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);

這裡最重要的就是提供乙個io_event陣列給核心來copy完成的io請求到這裡,陣列的大小是io_setup時指定的maxevents。

timeout是指等待io完成的超時時間,設定為null表示一直等待所有到io的完成。

4.銷毀io任務

int io_destroy (io_context_t ctx);

在非同步程式設計中,任何乙個環節的阻塞都會導致整個程式的阻塞,所以一定要避免在io_getevents呼叫時阻塞式的等待。還記得io_iocb_common中的flags和resfd嗎?看看libaio是如何提供io_getevents和事件迴圈的結合:

void io_set_eventfd(struct iocb *iocb, int eventfd)

這裡的resfd是通過系統呼叫eventfd生成的。

int eventfd(unsigned int initval, int flags);

eventfd是linux 2.6.22核心之後加進來的syscall,作用是核心用來通知應用程式發生的事件的數量,從而使應用程式不用頻繁地去輪詢核心是否有時間發生,而是由核心將發生事件的數量寫入到該fd,應用程式發現fd可讀後,從fd讀取該數值,並馬上去核心讀取。

有了eventfd,就可以很好地將libaio和epoll事件迴圈結合起來:

1. 建立乙個eventfd

efd = eventfd(0, efd_nonblock | efd_cloexec);

2. 將eventfd設定到iocb中

io_set_eventfd(iocb, efd);

3. 交接aio請求

io_submit(ctx, num_events, iocb);

4. 建立乙個epollfd,並將eventfd加到epoll中

epfd = epoll_create(1);

epoll_ctl(epfd, epoll_ctl_add, efd, &epevent);

epoll_wait(epfd, &epevent, 1, -1);

5. 當eventfd可讀時,從eventfd讀出完成io請求的數量,並呼叫io_getevents獲取這些io

以上就是linux 非同步io程式設計的一些基礎知識,希望對感興趣的同學或多或少有些幫忙,謝謝。

linux非同步IO程式設計例項分析

在direct io模式下,非同步是非常有必要的 因為繞過了pagecache,直接和磁碟互動 linux native aio正是基於這種場景設計的,具體的介紹見 kernel asynchronousi o aio support forlinux。下面我們就來分析一下aio程式設計的相關知識。...

網路程式設計之IO模型 非同步IO

linux下的asynchronous io其實用得不多,從核心2.6版本才開始引入。先看一下它的流程 使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何bl...

Linux 核心101 非同步IO

posix 非同步 io inte ce aio 定義了允許程序建立乙個或多個非同步的 io 操作的介面。程序可以在 io 操作完成之後得到作業系統的通知,手段包括 不通知 訊號 例項化thread。注意 這只是 posix the portable operating system inte ce...