linux下aio异步读写详解与实例
1.為什么會有異步I/O
aio異步讀寫是在linux內核2.6之后才正式納入其標準。之所以會增加此模塊,是因為眾所周知我們計算機CPU的執行速度遠大于I/O讀寫的執行速度,如果我們用傳統的阻塞式或非阻塞式來操作I/O的話,那么我們在同一個程序中(不用多線程或多進程)就不能同時操作倆個以上的文件I/O,每次只能對一個文件進行I/O操作,很明顯這樣效率很低下(因為CPU速度遠大于I/O操作的速度,所以當執行I/O時,CPU其實還可以做更多的事)。因此就誕生了相對高效的異步I/O
2.異步I/O的基本概念
所謂異步I/O即我們在調用I/O操作時(讀或寫)我們的程序不會阻塞在當前位置,而是在繼續往下執行。例如當我們調用異步讀API aio_read()時,程序執行此代碼之后會接著運行此函數下面的代碼,并且與此同時程序也在進行剛才所要讀的文件的讀取工作,但是具體什么時候讀完是不確定的
3.異步aio的基本API
| aio_read | 異步讀操作 |
| aio_write | 異步寫操作 |
| aio_error | 檢查異步請求的狀態 |
| aio_return | 獲得異步請求完成時的返回值 |
| aio_suspend | 掛起調用進程,直到一個或多個異步請求已完成 |
| aio_cancel | 取消異步請求 |
| lio_list | 發起一系列異步I/O請求 |
上述的每個API都要用aiocb結構體賴進行操作
aiocb的結構中常用的成員有
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
4異步I/O操作的具體使用
(1)異步讀aio_read
aio_read函數請求對一個文件進行讀操作,所請求文件對應的文件描述符可以是文件,套接字,甚至管道其原型如下
int aio_read(struct aiocb *paiocb);- 1
該函數請求對文件進行異步讀操作,若請求失敗返回-1,成功則返回0,并將該請求進行排隊,然后就開始對文件的異步讀操作
需要注意的是,我們得先對aiocb結構體進行必要的初始化
具體實例如下
aio_read
#include<stdio.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<assert.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/types.h> #include<fcntl.h> #include<aio.h>#define BUFFER_SIZE 1024int MAX_LIST = 2;int main(int argc,char **argv) {//aio操作所需結構體struct aiocb rd;int fd,ret,couter;fd = open("test.txt",O_RDONLY);if(fd < 0){perror("test.txt");}//將rd結構體清空bzero(&rd,sizeof(rd));//為rd.aio_buf分配空間rd.aio_buf = malloc(BUFFER_SIZE + 1);//填充rd結構體rd.aio_fildes = fd;rd.aio_nbytes = BUFFER_SIZE;rd.aio_offset = 0;//進行異步讀操作ret = aio_read(&rd);if(ret < 0){perror("aio_read");exit(1);}couter = 0; // 循環等待異步讀操作結束while(aio_error(&rd) == EINPROGRESS){printf("第%d次\n",++couter);}//獲取異步讀返回值ret = aio_return(&rd);printf("\n\n返回值為:%d",ret);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
上述實例中aiocb結構體用來表示某一次特定的讀寫操作,在異步讀操作時我們只需要注意4點內容
1.確定所要讀的文件描述符,并寫入aiocb結構體中(下面幾條一樣不再贅余)
2.確定讀所需的緩沖區
3.確定讀的字節數
4.確定文件的偏移量
總結以上注意事項:基本上和我們的read函數所需的條件相似,唯一的區別就是多一個文件偏移量
值得注意的是上述代碼中aio_error是用來獲取其參數指定的讀寫操作的狀態的
其原型如下
- 1
當其狀態處于EINPROGRESS則I/O還沒完成,當處于ECANCELLED則操作已被取消,發生錯誤返回-1
而aio_return則是用來返回其參數指定I/O操作的返回值
其原型如下
- 1
如果操作沒完成調用此函數,則會產生錯誤
特別提醒在編譯上述程序時必須在編譯時再加一個-lrt
上述代碼運行結果如下
(2)異步寫aio_write
aio_writr用來請求異步寫操作
其函數原型如下
- 1
aio_write和aio_read函數類似,當該函數返回成功時,說明該寫請求以進行排隊(成功0,失敗-1)
其和aio_read調用時的區別是就是我們如果在打開文件是,flags設置了O_APPEND則我們在填充aiocb時不需要填充它的偏移量了
具體實例如下
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
具體運行結果請讀者自己去試試
(3)使用aio_suspend阻塞異步I/O
aio_suspend函數可以時當前進程掛起,知道有向其注冊的異步事件完成為止
該函數原型如下
- 1
第一個參數是個保存了aiocb塊地址的數組,我們可以向其內添加想要等待阻塞的異步事件,第二個參數為向cblist注冊的aiocb個數,第三個參數為等待阻塞的超時事件,NULL為無限等待
具體使用如下
suspend:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
(4)lio_listio函數
aio同時還為我們提供了一個可以發起多個或多種I/O請求的接口lio_listio
這個函數效率很高,因為我們只需一次系統調用(一次內核上下位切換)就可以完成大量的I/O操作
其函數原型如下
- 1
第一個參數mode可以有倆個實參,LIO_WAIT和LIO_NOWAIT,前一個會阻塞該調用直到所有I/O都完成為止,后一個則會掛入隊列就返回
具體實例如下
lio_listio
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
5.I/O完成時進行異步通知
當我們的異步I/O操作完成之時,我們可以通過信號通知我們的進程也可用回調函數來進行異步通知,接下來我會為大家主要介紹以下回調函數來進行異步通知,關于信號通知有興趣的同學自己去學習吧
使用回調進行異步通知
該種通知方式使用一個系統回調函數來通知應用程序,要想完成此功能,我們必須在aiocb中設置我們想要進行異步回調的aiocb指針,以用來回調之后表示其自身
實例如下
aio線程回調通知
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
線程會掉是通過使用aiocb結構體中的aio_sigevent結構體來控制的,
其定義如下
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
總結
以上是生活随笔為你收集整理的linux下aio异步读写详解与实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 慢慢聊Linux AIO
- 下一篇: linux AIO (异步IO) 那点事