linux异步IO
異步IO
回顧同時讀鍵盤、鼠標的方法
異步IO的原理
前面四種方式都是主動去讀,對于read函數來說它并不知道是不是一定有數據,如果有數據就讀到數據,沒有數據要么阻塞直到讀到數據為止,要么不阻塞。
這就好比我想去澡堂洗澡,我不知道有沒有位置,我去了后如果有位置我就立即洗澡(立即讀數據),如果沒有位置要么等(阻塞讀),要么離開過段時間再來看(非阻塞讀)。
實際上除了以上描述符的方式外,還有另外一種聰明的方式,那就是使用異步IO的方式來實現。
異步IO的原理就是,底層把數據準備好后,內核就會給進程發送一個“異步通知的信號”通知進程,表示數據準備好了,然后調用信號處理函數去讀數據,在沒有準備好時,進程忙自己的事情。
這就好比我跟澡堂老板說一聲“有位置了打電話給我哈”,我就會去該干嘛就干嘛,等老板通知我了我就知道有位置了,這樣的方式不就更好嗎?
比如使用異步IO讀鼠標,底層鼠標驅動就把數據準備好后,會發一個“SIGIO”(異步通知的信號)給進程,進程調用捕獲函數讀鼠標,讀鼠標的SIGIO捕獲函數需要我們自己定義。
使用異步IO方式讀鼠標讀鍵盤
進程正常阻塞讀鍵盤,然后將讀鼠標設置為異步IO方式。
進程正常阻塞讀鍵盤時,如果鼠標沒有數據的話,進程不關心讀鼠標的事情,如果鼠標數據來了,底層鼠標驅動會向
進程發送一個SIGIO信號,然后調用注冊的SIGIO信號捕獲函數讀鼠標數據。
當然也可以反過來,進程正常阻塞讀鼠標,然后將讀鍵盤設置為異步IO方式。
異步IO這個名字怎么理解?
比如以異步IO方式讀鼠標數據為例,如果知道什么時候數據會來,等這個時間到時再去讀數據,這就是步調統一的同步讀。
如果不知道什么時候會有數據來,這種就只能是什么時候數據來了就什么時候讀,這種就是異步讀。
之所以叫異步,是因為我不知道你什么時候來,沒辦法統一步調(異步的),只能是隨時來隨時讀。
使用異步IO要有兩個前提
應用層進行異步IO設置時,使用的也是fcntl函數。
使用異步IO,應用層的設置步驟
調用signal函數對SIGIO信號設置捕獲函數
- 在捕獲函數里面實現讀操作,比如讀鼠標。
使用fcntl函數,將接收SIGIO信號的進程設置為當前進程
- 如果不設置,底層驅動并不知道將SIGIO信號發送給哪一個進程
- fcntl(mousefd, F_SETOWN, getpid()); /* 將當前進程的進程號告訴給內核 */
F_GETOWN
獲取當前在文件描述符 fd上接收到SIGIO 或 SIGURG事件信號的進程ID或進程組,arg忽略。
F_SETOWN
設置在文件描述符fd上接收SIGIO 或 SIGURG事件信號的進程ID或進程組ID,值為arg。
使用fcntl函數,對文件描述符增設O_ASYNC的狀態標志,讓fd支持異步IO
- mousefd = open("/dev/input/mouse1", O_RDONLY);
- flag = fcntl(mousefd, F_GETFL);
- flag |= O_ASYNC; //補設O_ASYNC
- fcntl(mousefd, F_SETFL, flag);/* 設置進程啟用異步通知功能 */
代碼演示:
void signal_fun(int signo) {int buf;int ret = 0;if (SIGIO == signo){bzero(&buf, sizeof(buf));ret = read(mousefd, &buf, sizeof(buf));if (ret > 0) printf("%d\n", buf);} }int main(int argc, char *argv[]) {int ret = 0;char buf[100] = {0};struct pollfd fds[2];mousefd = open("/dev/input/mouse0", O_RDONLY);if (mousefd == -1) print_err("open /dev/input/mouse0 fail", __LINE__, errno);/* 為SIGIO設置捕獲函數,在捕獲函數里面讀鼠標 */signal(SIGIO, signal_fun);/* 告訴鼠標驅動,它發送的SIGIO信號由當前進程接收 */fcntl(mousefd, F_SETOWN, getpid());/* 對mousefd進行設置讓其支持異步IO */int flag = fcntl(mousefd, F_GETFL);flag |= O_ASYNC;fcntl(mousefd, F_SETFL, flag);while(1){bzero(buf, sizeof(buf));ret = read(0, buf, sizeof(buf));if (ret > 0) printf("%s\n", buf);}return 0; }總結
- 上一篇: 网络基础:Ping命令的7种基础用法,掌
- 下一篇: Jupyter notebook 入门教